simple callerID app?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts
  • Bill Scharf
    Member
    • Aug 2003
    • 123

    simple callerID app?

    About two years I first attempted to create a caller ID app in PB (http://www.powerbasic.com/support/pb...ad.php?t=14238). After a few weeks I had to move on to other projects. Well now I am back on this project and still searching for success. The same requirements apply:
    1. No specialized external hardware allowed
    2. No third party dll's or controls allowed
    3. Win 9x-Vista support

    I have tried to adapt Mike Trader's example at (http://www.powerbasic.com/support/pb...ad.php?t=24743) to display caller ID information. Here is the entire adapted example:
    Code:
    #COMPILE EXE "TAPI09.exe" 
    #DIM ALL   
                  
    %TAPI_CURRENT_VERSION = &h00020000 ' Version 2.0
                
    #IF %TAPI_CURRENT_VERSION >= &h000020000 ' for completeness
      '  These constants are mutually exclusive - there's no way to specify more
      '  than one AT a time (AND it doesn't make sense, either) so they're ordinal rather than bits.
      %LINEINITIALIZEEXOPTION_USEHIDDENWINDOW    = &h00000001  '  TAPI v2.0
      %LINEINITIALIZEEXOPTION_USEEVENT           = &h00000002  '  TAPI v2.0
      %LINEINITIALIZEEXOPTION_USECOMPLETIONPORT  = &h00000003  '  TAPI v2.0
    #ENDIF
    #INCLUDE "c:\pbwin80\winapi\WIN32API.INC"
    #INCLUDE "TAPI32.INC"
                  
    DECLARE FUNCTION CreateConnection( sTitle AS STRING, TotDev AS DWORD ) AS STRING
    DECLARE FUNCTION NegotiateAPIversions( TotDev AS DWORD, AppAPIver AS DWORD  ) AS STRING
    DECLARE FUNCTION GetLineDevCaps( TotDev AS DWORD ) AS STRING
    DECLARE FUNCTION GetTAPIStructString( BYVAL ptrTapistruct AS LONG, BYVAL offset AS LONG, BYVAL length AS LONG ) AS STRING
    DECLARE FUNCTION DeviceInfo( Dev AS LONG ) AS STRING
    DECLARE FUNCTION DeviceConfigDialog( BYVAL Dev AS LONG, BYVAL OwnerHwnd AS LONG ) AS STRING
    DECLARE FUNCTION DialingPropertiesDialog( BYVAL Dev AS LONG, BYVAL OwnerHwnd AS LONG, AppAPIver AS DWORD ) AS STRING
    DECLARE FUNCTION OpenLine( Dev AS LONG ) AS STRING
    DECLARE FUNCTION ProcessCanonical( hLineApp AS LONG, Dev AS LONG ) AS STRING
    DECLARE FUNCTION MakeCallAsynch( zNumToDial AS ASCIIZ*%MAX_PATH ) AS STRING
    DECLARE FUNCTION DropCallAsynch( ) AS STRING
    DECLARE FUNCTION DeallocateCall( ) AS STRING
    DECLARE FUNCTION CloseLine( )      AS STRING
    DECLARE FUNCTION ShutdownLine( )   AS STRING
    DECLARE FUNCTION PaintDevIcon( BYVAL Dev AS LONG, hIcon AS LONG ) AS STRING
    DECLARE FUNCTION ShowText( sTxt AS STRING ) AS LONG
    DECLARE FUNCTION lineCallbackFunc( BYVAL hDevice AS DWORD, BYVAL dwMsg AS DWORD, BYVAL dwCallbackInstance AS DWORD, _
                     BYVAL dwParam1 AS DWORD,BYVAL dwParam2 AS DWORD,BYVAL dwParam3 AS DWORD ) AS LONG
    
    TYPE TapiLineTYPE  
        zLineName               AS ASCIIZ*%MAX_PATH ' dwLineNameOffset,     dwLineNameSize)
        zProviderInfo           AS ASCIIZ*%MAX_PATH ' dwProviderInfoOffset, dwProviderInfoSize)
        zSwitchInfo             AS ASCIIZ*%MAX_PATH ' dwSwitchInfoOffset,   dwSwitchInfoSize)
        CurrentLineID           AS DWORD            ' Device Number
        PermanentLineID         AS DWORD            ' dwPermanentLineID
        StringFormat            AS DWORD            ' dwStringFormat 
        numAddresses            AS DWORD            ' dwNumAddresses
        maxDataRate             AS DWORD            ' dwMaxRate
        BearerModes             AS DWORD            ' dwBearerModes
        AddressModes            AS DWORD            ' dwAddressModes
        MediaModes              AS DWORD            ' dwMediaModes
        GenerateToneMaxNumFreq  AS DWORD            ' dwGenerateToneMaxNumFreq
        GenerateToneModes       AS DWORD            ' dwGenerateToneModes
        numTerminals            AS DWORD            ' dwNumTerminals 
                                                    
        NegAPIver               AS DWORD            ' Negotiated API Version
        ExtAPIver               AS LINEEXTENSIONID  ' Extension API versions 
        LineSupportsVoiceCalls  AS LONG             ' Can make a voice call 
                    
        zNumToDial              AS ASCIIZ*%MAX_PATH ' Number user wants to dial
        zDialableString         AS ASCIIZ*%MAX_PATH ' Contains all info
        zDisplayableString      AS ASCIIZ*%MAX_PATH ' Does not display Credit card info
        CurrentCountry          AS DWORD            ' Country/region code configured in CurrentLocation
        DestCountry             AS DWORD            ' Destination country/region code of the translated address
        TranslateResults        AS DWORD            ' Code to string contents 
        TranslateDefn           AS STRING*48        ' Explanation of Translation Result
    END TYPE  
    GLOBAL TapiLine() AS TapiLineTYPE 
    
    GLOBAL RequestingCall, DroppingCall AS LONG  ' Global call state flags
    GLOBAL hDbg, hDlg, hCall, hLine, hLineApp, Done AS LONG  
    GLOBAL lpfnCallback AS DWORD ' pointer to the function callback 
    
    %LoAPI = &H10003  ' default TAPI 1.3 (&H00010003)  ' %EARLY_TAPI_VERSION   
    %HiAPI = &H30000  ' default TAPI 3.0 (&H00030000)  ' %TAPI_CURRENT_VERSION 
                
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION CreateConnection( sTitle AS STRING, TotDev AS DWORD ) AS STRING
                         
      LOCAL RetVal, hInstance AS LONG 
      LOCAL lpNumDevs AS DWORD 
      LOCAL zTemp AS ASCIIZ * 255     
      LOCAL lpfnCallBack AS LONG PTR
      LOCAL lip AS LINEINITIALIZEEXPARAMS
                              
                     
        FUNCTION = "" ' no problems   
        ShowText "Initializing TAPI & Enumerating Lines"
        zTemp = sTitle ' 
        hInstance = 0
        lip.dwTotalSize = LEN(lip) 'init params   
        lip.dwOptions   = %LINEINITIALIZEEXOPTION_USEHIDDENWINDOW
                                                   
    ' What is important to notice regarding lineInitializeEx is that
    ' you can SELECT one OF two mechanisms by which TAPI will NOTIFY the
    ' application OF telephony events: Hidden Window OR Event HANDLE.
    ' In this example we are using Hidden Window.
    ' When the hidden window method of notification is used in a TAPI application, TAPI creates a hidden 
    ' window for the application in the context of the thread that called lineInitializeEx. If the thread that 
    ' calls lineInitializeEx does not retrieve and dispatch windows messages, the hidden window does not 
    ' receive Windows messages, and in turn, the callback function registered by the TAPI application is not called.
    ' Calling lineInitialize is equivalent to calling lineInitializeEx with the LINEINITIALIZEEXOPTION_USEHIDDENWINDOW
    ' option, so using lineInitialize instead of lineInitializeEx results in the same behavior. 
    ' Make sure the thread that calls lineInitializeEx contains a message loop that retrieves and 
    ' dispatches messages for the hidden window. 
    msgbox "lineInitializeEx within create connection"
        lpfnCallBack = CODEPTR(lineCallbackFunc) '  Pointer to Callback Function
        RetVal = lineInitializeEx(  hLineApp, _  '  LPHLINEAPP     lphLineApp          - HANDLE used in all TAPI functions calls                 
                                   hInstance, _  '  HINSTANCE      hInstance           - EXEorDLL instance HANDLE                     
                          BYVAL lpfnCallBack, _  '  LINECALLBACK   lpfnCallback        - CALLBACK FUNCTION TO return asynchronous notifications                  
                                       zTemp, _  '  LPCWSTR        lpszFriendlyAppName - NAME TO indicate who is calling TAPI                    
                                   lpNumDevs, _  '  LPDWORD        lpdwNumDevs         - Number of available TAPI devices, 0 to dwNumDevices-1                    
                                      %HiAPI, _  '  LPDWORD        lpdwAPIVersion      - Negotiate TAPI Version                   
                                         lip)    '  LPLINEINITIALIZEEXPARAMS lip       - Hidden Window OR Event HANDLE
                                                 '  Returns 0 if successful
    
        IF RetVal <> 0 THEN 
            SELECT CASE CDWD(RetVal)
              CASE %LINEERR_INVALAPPNAME    : FUNCTION = "Invalid application name" 
              CASE %LINEERR_OPERATIONFAILED : FUNCTION = "the operation failed"
              CASE %LINEERR_INIFILECORRUPT  : FUNCTION = "the INI file is corrupted"
              CASE %LINEERR_INVALPOINTER    : FUNCTION = "Invalid pointer"
              CASE %LINEERR_REINIT          : FUNCTION = "the application attempted to initialize TAPI twice"
              CASE %LINEERR_NOMEM           : FUNCTION = "No memory available"
              CASE %LINEERR_INVALPARAM      : FUNCTION = "Invalid parameter"
              CASE ELSE                     : FUNCTION = "Undefined Error"+STR$(RetVal) + " = &H" + HEX$(RetVal)
            END SELECT
            EXIT FUNCTION 
        END IF 
        '================================
                           
        IF lpNumDevs = 0 THEN 
            FUNCTION = "No TAPI Devices found" 'no lines! 
            TotDev = 0
        ELSE   
            TotDev = lpNumDevs-1 
        END IF 
        '================================
                         
    END FUNCTION 
                           
                
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION NegotiateAPIversions( TotDev AS DWORD, AppAPIver AS DWORD ) AS STRING
                   
      LOCAL RetVal AS LONG 
      LOCAL Dev AS DWORD   
      LOCAL lxid AS LINEEXTENSIONID
                        
                  
        FUNCTION = "" ' no problems 
        ShowText "Negotiating API ver for lines"
        REDIM TapiLine(TotDev)
        FOR Dev = 0 TO TotDev   ' negotiate and cache API versions for each line
          RetVal = lineNegotiateAPIVersion( hLineApp, Dev, %LoAPI, %HiAPI, TapiLine(Dev).NegAPIver, lxid) ' Returns a LONG
         'PRINT #hDbg, STR$(Dev) + ",  Negotiated API ver=" + STR$(HI(WORD,TapiLine(Dev).NegAPIver)) + "." + STR$(Lo(WORD,TapiLine(Dev).NegAPIver))
          IF RetVal <> 0 THEN            
            SELECT CASE CDWD(RetVal)
              CASE %LINEERR_BADDEVICEID            : FUNCTION = "the device identifier provided is incorrect" 
              CASE %LINEERR_NODRIVER               : FUNCTION = "No driver was found"
              CASE %LINEERR_INCOMPATIBLEAPIVERSION : FUNCTION = "the API version is incompatible"
              CASE %LINEERR_OPERATIONFAILED        : FUNCTION = "the operation failed"
              CASE %LINEERR_INVALAPPHANDLE         : FUNCTION = "the Application handle was invalid"
              CASE %LINEERR_RESOURCEUNAVAIL        : FUNCTION = "the resource is unavailable"
              CASE %LINEERR_INVALPOINTER           : FUNCTION = "the pointer is invalid"
              CASE %LINEERR_UNINITIALIZED          : FUNCTION = "the parameter is uninitialized"
              CASE %LINEERR_NOMEM                  : FUNCTION = "No memory is available"
              CASE %LINEERR_OPERATIONUNAVAIL       : FUNCTION = "the operation is unavailable"
              CASE %LINEERR_NODEVICE               : TapiLine(Dev).zLineName = "Device not found" : ITERATE ' Handle this differently 
              CASE ELSE                            : FUNCTION = "Undefined Error"+STR$(RetVal)
            END SELECT  ' "Device not Found" can occur on a laptop with PCMCIA card coming out of hibernation.
            TapiLine(Dev).NegAPIver = 0 'no compatible API negotiated for this line
            EXIT FUNCTION  
          ELSE  ' PRINT #hDbg, "ExtAPIversions=" + STR$(lxid.dwExtensionID0) + STR$(lxid.dwExtensionID1) + STR$(lxid.dwExtensionID2) + STR$(lxid.dwExtensionID3)
          ' If the service provider for the specified dwDeviceID parameter supports provider-specific extensions, 
          ' then, upon a successful negotiation, this structure is filled with the extension identifier of 
          ' these extensions. This structure contains all zeros if the line provides no extensions. An application 
          ' can ignore the returned parameter if it does not use extensions.
            TapiLine(Dev).ExtAPIver.dwExtensionID0 = lxid.dwExtensionID0 ' Save extension version (dev-specific features) if available
            TapiLine(Dev).ExtAPIver.dwExtensionID1 = lxid.dwExtensionID1
            TapiLine(Dev).ExtAPIver.dwExtensionID2 = lxid.dwExtensionID2
            TapiLine(Dev).ExtAPIver.dwExtensionID3 = lxid.dwExtensionID3
            IF TapiLine(Dev).NegAPIver > AppAPIver THEN  AppAPIver = TapiLine(Dev).NegAPIver ' highest ver found 
          END IF    
        NEXT
    END FUNCTION 
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION GetLineDevCaps( TotDev AS DWORD ) AS STRING  
    ' This function queries a specified line device to determine its telephony capabilities. 
    ' the returned data is valid for all addresses on the line device
                                
    ' lineGetDevCaps(BYVAL hLineApp AS DWORD, BYVAL dwDeviceID AS DWORD, BYVAL dwAPIVersion AS DWORD, BYVAL dwExtVersion AS DWORD, lpLineDevCaps AS LINEDEVCAPS)
      LOCAL RetVal, lpData, NumElem AS LONG 
      LOCAL Dev AS DWORD 
                          
      LOCAL LineCaps() AS LINEDEVCAPS ' variable-length structures that TAPI may throw at you 
                
        FUNCTION = "" ' no problems    
        ShowText "Getting Line Device Info"
         
        ' NOTE: dwNeededSize will return zero if the memory size is too small to start with hence
        ' the test for %LINEERR_STRUCTURETOOSMALL right after the function call. This test alone
        ' is not sufficient as the function may not return this error when the TotalSize is still 
        ' less than the NeededSize! Hence the test for both. 
        ' RetVal is a LONG variable yet the Constant is defined as a DWORD in tapi32.inc hence 
        ' the need to convert RetVal to a DWORD. Of course none of this is in MSDN.... 
        NumElem = 1 ' Starting memory size
        DIM LineCaps(NumElem-1)  ' First attempt
        LineCaps(0).dwTotalSize = SIZEOF(LINEDEVCAPS) * NumElem ' Size of the UDT 
        FOR Dev = 0 TO TotDev  
          IF TapiLine(Dev).NegAPIver = 0 THEN ITERATE ' not found in API negotiation
          DO
            RetVal = lineGetDevCaps( hLineApp, Dev, TapiLine(Dev).NegAPIver, 0, LineCaps(0) ) 'request TAPI to fill UDT with info     
            IF CDWD(RetVal) = %LINEERR_STRUCTURETOOSMALL OR LineCaps(0).dwTotalSize < LineCaps(0).dwNeededSize  THEN ' increase buffer size
           'PRINT #hDbg, STR$(Dev) + ", NumElem=" + STR$(NumElem) + ",  TotalSize=" + STR$(LineCaps(0).dwTotalSize) + ",  NeededSize=" + STR$(LineCaps(0).dwNeededSize) 
              INCR NumElem ' Once increased, just leave it that size for next device
              IF NumElem > 20 THEN  ' Something else is wrong 
                FUNCTION = "Memory increased x"+STR$(NumElem)+" and still not big enough for LineCaps!"
                EXIT FUNCTION
              END IF ' 
              REDIM LineCaps(NumElem-1) ' assign more memory 
              LineCaps(0).dwTotalSize = SIZEOF(LINEDEVCAPS) * NumElem
            ELSE ' PRINT #hDbg, STR$(Dev) + ", NumElem=" + STR$(NumElem) + ",  TotalSize=" + STR$(LineCaps(0).dwTotalSize) + ",  NeededSize=" + STR$(LineCaps(0).dwNeededSize) 
              EXIT LOOP  
            END IF
          LOOP
          '================================
                              
          IF RetVal <> 0 THEN            
            SELECT CASE CDWD(RetVal) 
              CASE %LINEERR_STRUCTURETOOSMALL      : FUNCTION = "the structure is too small" ' buffer size is too small
              CASE %LINEERR_BADDEVICEID            : FUNCTION = "Bad device id provided" 
              CASE %LINEERR_NOMEM                  : FUNCTION = "No memory is available"
              CASE %LINEERR_INCOMPATIBLEAPIVERSION : FUNCTION = "API version is incompatible"
              CASE %LINEERR_OPERATIONFAILED        : FUNCTION = "the operation failed"
              CASE %LINEERR_INCOMPATIBLEEXTVERSION : FUNCTION = "Extension version is incompatible"
              CASE %LINEERR_RESOURCEUNAVAIL        : FUNCTION = "the resource is unavailable"
              CASE %LINEERR_INVALAPPHANDLE         : FUNCTION = "the Application Handle is invalid"
              CASE %LINEERR_INVALPOINTER           : FUNCTION = "Invalid pointer"
              CASE %LINEERR_UNINITIALIZED          : FUNCTION = "the parameter is uninitialized"
              CASE %LINEERR_NODRIVER               : FUNCTION = "No driver was found"
              CASE %LINEERR_OPERATIONUNAVAIL       : FUNCTION = "the operation is unavailable"
              CASE %LINEERR_NODEVICE               : FUNCTION = "No device was found"  
              CASE ELSE                            : FUNCTION = "Undefined Error"+STR$(RetVal)
            END SELECT 
            EXIT FUNCTION   
          END IF 
          '================================  
                      
          'store UDT info in class local variables   
          TapiLine(Dev).CurrentLineID           = Dev
          TapiLine(Dev).zLineName               = GetTAPIStructString(VARPTR(LineCaps(0)), LineCaps(0).dwLineNameOffset,     LineCaps(0).dwLineNameSize)
          TapiLine(Dev).zProviderInfo           = GetTAPIStructString(VARPTR(LineCaps(0)), LineCaps(0).dwProviderInfoOffset, LineCaps(0).dwProviderInfoSize)
          TapiLine(Dev).zSwitchInfo             = GetTAPIStructString(VARPTR(LineCaps(0)), LineCaps(0).dwSwitchInfoOffset,   LineCaps(0).dwSwitchInfoSize)
          TapiLine(Dev).PermanentLineID         = LineCaps(0).dwPermanentLineID
          TapiLine(Dev).StringFormat            = LineCaps(0).dwStringFormat
          TapiLine(Dev).numAddresses            = LineCaps(0).dwNumAddresses
          TapiLine(Dev).maxDataRate             = LineCaps(0).dwMaxRate
          TapiLine(Dev).BearerModes             = LineCaps(0).dwBearerModes
          TapiLine(Dev).AddressModes            = LineCaps(0).dwAddressModes
          TapiLine(Dev).MediaModes              = LineCaps(0).dwMediaModes
          TapiLine(Dev).GenerateToneMaxNumFreq  = LineCaps(0).dwGenerateToneMaxNumFreq
          TapiLine(Dev).GenerateToneModes       = LineCaps(0).dwGenerateToneModes
          TapiLine(Dev).numTerminals            = LineCaps(0).dwNumTerminals  
          '================================
                      
          IF %LINEBEARERMODE_VOICE AND TapiLine(Dev).BearerModes THEN 'check if line supports making voice calls
              IF %LINEMEDIAMODE_INTERACTIVEVOICE AND TapiLine(Dev).mediamodes THEN
                TapiLine(Dev).LineSupportsVoiceCalls = 1
              END IF
          END IF  
          '================================ 
                
          COMBOBOX ADD hDlg, 98, STR$(Dev) + " - " + TRIM$(TapiLine(Dev).zLineName) ' add the device to the combobox 
          '================================  
        NEXT  
     
    END FUNCTION    
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION GetTAPIStructString(BYVAL ptrTapistruct AS LONG, BYVAL offset AS LONG, BYVAL length AS LONG) AS STRING
      LOCAL sTemp AS STRING
                   
        FUNCTION = "" 
        IF length THEN ' handle erroneous input
          IF offset THEN ' 
            sTemp = SPACE$(length)
            CopyMemory BYVAL STRPTR(sTemp), BYVAL ptrTapistruct+offset, length
            FUNCTION = sTemp 
          END IF        
        END IF  
        '================================ 
    END FUNCTION 
                 
           
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION DeviceInfo( Dev AS LONG ) AS STRING
                       
      LOCAL sTemp, sMsg AS STRING
                          
        sMsg = ""  
        sMsg = sMsg + "TAPI LINE NAME: " + TapiLine(Dev).zLineName  + $CRLF  
        sMsg = sMsg + "TAPI LINE: #" + STR$(TapiLine(Dev).CurrentLineID) + $CRLF '
        sMsg = sMsg + "TAPI PROVIDER INFO: " + TapiLine(Dev).zProviderInfo  + $CRLF
        sMsg = sMsg + "TAPI SWITCH INFO: " + TapiLine(Dev).zSwitchInfo  + $CRLF
        sMsg = sMsg + $CRLF + "Permanent Line ID: " + STR$(TapiLine(Dev).PermanentLineID) + $CRLF
        SELECT CASE TapiLine(Dev).StringFormat
            CASE %STRINGFORMAT_ASCII
                sMsg = sMsg + "String Format: STRINGFORMAT_ASCII"  + $CRLF
            CASE %STRINGFORMAT_DBCS
                sMsg = sMsg + "String Format: STRINGFORMAT_DBCS"  + $CRLF
            CASE %STRINGFORMAT_UNICODE
                sMsg = sMsg + "String Format: STRINGFORMAT_UNICODE" + $CRLF
            CASE %STRINGFORMAT_BINARY
                sMsg = sMsg + "String Format: STRINGFORMAT_BINARY" + $CRLF
            CASE ELSE
        END SELECT
        sMsg = sMsg + "Number of addresses associated with this line: " + STR$(TapiLine(Dev).numAddresses) + $CRLF
        sMsg = sMsg + "Max data rate: " + STR$(TapiLine(Dev).maxDataRate) + $CRLF
        sMsg = sMsg + $CRLF + "Bearer Modes supported:" + $CRLF 
        IF %LINEBEARERMODE_VOICE  AND TapiLine(Dev).BearerModes THEN sMsg = sMsg + $TAB + "LINEBEARERMODE_VOICE" + $CRLF
        IF %LINEBEARERMODE_SPEECH AND TapiLine(Dev).BearerModes THEN sMsg = sMsg + $TAB + "LINEBEARERMODE_SPEECH" + $CRLF
        IF %LINEBEARERMODE_DATA   AND TapiLine(Dev).BearerModes THEN sMsg = sMsg + $TAB + "LINEBEARERMODE_DATA"  + $CRLF
        IF %LINEBEARERMODE_ALTSPEECHDATA AND TapiLine(Dev).BearerModes THEN sMsg = sMsg + $TAB + "LINEBEARERMODE_ALTSPEECHDATA" + $CRLF
        IF %LINEBEARERMODE_MULTIUSE AND TapiLine(Dev).BearerModes THEN sMsg = sMsg + $TAB + "LINEBEARERMODE_MULTIUSE"  + $CRLF
        IF %LINEBEARERMODE_NONCALLSIGNALING AND TapiLine(Dev).BearerModes THEN sMsg = sMsg + $TAB + "LINEBEARERMODE_NONCALLSIGNALING" + $CRLF
        sMsg = sMsg + $CRLF + "Address Modes supported:" + $CRLF
        IF TapiLine(Dev).AddressModes AND %LINEADDRESSMODE_ADDRESSID THEN sMsg = sMsg + $TAB + "LINEADDRESSMODE_ADDRESSID"  + $CRLF
        IF TapiLine(Dev).AddressModes AND %LINEADDRESSMODE_DIALABLEADDR THEN sMsg = sMsg + $TAB + "LINEADDRESSMODE_DIALABLEADDR" + $CRLF
        sMsg = sMsg + $CRLF + "Media Modes supported:" + $CRLF
        IF %LINEMEDIAMODE_ADSI AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_ADSI" + $CRLF
        IF %LINEMEDIAMODE_AUTOMATEDVOICE AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_AUTOMATEDVOICE" + $CRLF
        IF %LINEMEDIAMODE_DATAMODEM AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_DATAMODEM"  + $CRLF
        IF %LINEMEDIAMODE_DIGITALDATA AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_DIGITALDATA"  + $CRLF
        IF %LINEMEDIAMODE_G3FAX AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_G3FAX"  + $CRLF
        IF %LINEMEDIAMODE_G4FAX AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_G4FAX"  + $CRLF
        IF %LINEMEDIAMODE_INTERACTIVEVOICE AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_INTERACTIVEVOICE" + $CRLF
        IF %LINEMEDIAMODE_MIXED AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_MIXED"  + $CRLF
        IF %LINEMEDIAMODE_TDD AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_TDD"  + $CRLF
        IF %LINEMEDIAMODE_TELETEX AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_TELETEX" + $CRLF
        IF %LINEMEDIAMODE_TELEX AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_TELEX"  + $CRLF
        IF %LINEMEDIAMODE_UNKNOWN AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_UNKNOWN"  + $CRLF
        IF %LINEMEDIAMODE_VIDEOTEX AND TapiLine(Dev).mediamodes THEN sMsg = sMsg + $TAB + "LINEMEDIAMODE_VIDEOTEX" + $CRLF
        sMsg = sMsg + $CRLF + "Line Tone Generation supported: " + STR$(TapiLine(Dev).GenerateToneMaxNumFreq) + $CRLF
        IF TapiLine(Dev).GenerateToneMaxNumFreq THEN 'show if tone generation is supported
            IF %LINETONEMODE_BEEP AND TapiLine(Dev).GenerateToneModes THEN sMsg = sMsg + $TAB + "LINETONEMODE_BEEP" + $CRLF
            IF %LINETONEMODE_BILLING AND TapiLine(Dev).GenerateToneModes THEN sMsg = sMsg + $TAB + "LINETONEMODE_BILLING"  + $CRLF
            IF %LINETONEMODE_BUSY AND TapiLine(Dev).GenerateToneModes THEN sMsg = sMsg + $TAB + "LINETONEMODE_BUSY"  + $CRLF
            IF %LINETONEMODE_CUSTOM AND TapiLine(Dev).GenerateToneModes THEN sMsg = sMsg + $TAB + "LINETONEMODE_CUSTOM" + $CRLF
            IF %LINETONEMODE_RINGBACK AND TapiLine(Dev).GenerateToneModes THEN sMsg = sMsg + $TAB + "LINETONEMODE_RINGBACK" + $CRLF
        END IF
        sMsg = sMsg + "Number of terminals for this line: " + STR$(TapiLine(Dev).numTerminals) + $CRLF 
      FUNCTION = sMsg  '
    END FUNCTION    
     
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION DeviceConfigDialog( BYVAL Dev AS LONG, BYVAL OwnerHwnd AS LONG ) AS STRING 
      LOCAL zTemp AS ASCIIZ*255 
      LOCAL RetVal AS LONG
                         
        FUNCTION = "" ' no problems 
        zTemp  = "" ' Highest level of config available
        RetVal = lineConfigDialog( TapiLine(Dev).CurrentLineID, OwnerHwnd, zTemp) 
                          
        IF RetVal <> 0 THEN 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_BADDEVICEID        : FUNCTION = "the device id is incorrect"
            CASE %LINEERR_NOMEM              : FUNCTION = "not enough memory is available"
            CASE %LINEERR_INUSE              : FUNCTION = "the line is in use"
            CASE %LINEERR_OPERATIONFAILED    : FUNCTION = "the operation failed"
            CASE %LINEERR_INVALDEVICECLASS   : FUNCTION = "the device class is invalid"
            CASE %LINEERR_RESOURCEUNAVAIL    : FUNCTION = "the resource is unavailable"
            CASE %LINEERR_INVALPARAM         : FUNCTION = "the parameter is invalid"
            CASE %LINEERR_UNINITIALIZED      : FUNCTION = "the parameter is uninitialized"
            CASE %LINEERR_INVALPOINTER       : FUNCTION = "the pointer is invalid"
            CASE %LINEERR_OPERATIONUNAVAIL   : FUNCTION = "the operation is unavailable"
            CASE %LINEERR_NODEVICE           : FUNCTION = "the device was not found"
            CASE ELSE                        : FUNCTION = "Undefined Error"+STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT  
        END IF   
        '================================
        
    END FUNCTION
         
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION DialingPropertiesDialog(BYVAL Dev AS LONG, BYVAL OwnerHwnd AS LONG, AppAPIver AS DWORD ) AS STRING
                           
      LOCAL RetVal AS LONG 
                          
        FUNCTION = "" ' no problems 
        RetVal = lineTranslateDialog(hLineApp, TapiLine(Dev).CurrentLineID, AppAPIver, OwnerHwnd, TapiLine(Dev).zNumToDial) 
                                
        IF RetVal <> 0 THEN 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_BADDEVICEID              : FUNCTION = "the device id is incorrect"
            CASE %LINEERR_INVALPARAM               : FUNCTION = "the parameter is invalid"
            CASE %LINEERR_INCOMPATIBLEAPIVERSION   : FUNCTION = "the API version is incompatible"
            CASE %LINEERR_INVALPOINTER             : FUNCTION = "the pointer is invalid"
            CASE %LINEERR_INIFILECORRUPT           : FUNCTION = "the INI file is corrupt"
            CASE %LINEERR_NODRIVER                 : FUNCTION = "the driver was not found"
            CASE %LINEERR_INUSE                    : FUNCTION = "the line is in use"
            CASE %LINEERR_NOMEM                    : FUNCTION = "not enough memory is available"
            CASE %LINEERR_INVALADDRESS             : FUNCTION = "the Address is invalid"
            CASE %LINEERR_INVALAPPHANDLE           : FUNCTION = "the application handle is invalid"
            CASE %LINEERR_OPERATIONFAILED          : FUNCTION = "the operation failed"  
            CASE ELSE                              : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
        END IF 
        '================================ 
    END FUNCTION
                 
          
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
    FUNCTION OpenLine( Dev AS LONG ) AS STRING  ' hLine is GLOBAL
      LOCAL privileges, mediamodes AS LONG 
      LOCAL RetVal AS LONG 
      LOCAL dwfnCallBack AS DWORD PTR
                         
               
                 
      ' dwPrivileges defines which privileges your application is
      ' interested in obtaining. Possible values are LINECALLPRIVILEGE_NONE,
      ' LINECALLPRIVILEGE_MONITOR, and LINECALLPRIVILEGE_OWNER. If you do not need
      ' any stuff on incoming calls, simply put LINECALLPRIVILEGE_NONE there. In
      ' case you really want to deal with incoming/outgoing calls, specify the
      ' appropriate privilege level. the dwMediaModes parameter is used only if
      ' LINECALLPRIVILEGE_OWNER is set. It declares which media modes are of
      ' interest for your application.
        'privileges = %LINECALLPRIVILEGE_NONE
        privileges = %LINECALLPRIVILEGE_MONITOR
        'mediamodes = %LINEMEDIAMODE_INTERACTIVEVOICE
    		mediamodes =%LINEMEDIAMODE_UNKNOWN  								OR _
    								%LINEMEDIAMODE_INTERACTIVEVOICE         OR _
    								%LINEMEDIAMODE_AUTOMATEDVOICE           OR _
    								%LINEMEDIAMODE_DATAMODEM                OR _
    								%LINEMEDIAMODE_G3FAX                    OR _
    								%LINEMEDIAMODE_TDD                      OR _
    								%LINEMEDIAMODE_G4FAX                    OR _
    								%LINEMEDIAMODE_DIGITALDATA              OR _
    								%LINEMEDIAMODE_TELETEX                  OR _'								%LINEMEDIAMODE_VIDEOTEX                 OR _
    								%LINEMEDIAMODE_TELEX                    OR _
    								%LINEMEDIAMODE_MIXED                    OR _
    								%LINEMEDIAMODE_ADSI                     OR _
    								%LINEMEDIAMODE_VOICEVIEW                
        '================================
                     
        FUNCTION = "" ' no problems 
        ShowText "Opening Line #" + STR$(Dev)
        IF hLine <> 0 THEN ' Check Line is not allready open  
            FUNCTION = "Line allready open on this device"
            EXIT FUNCTION    
        END IF       
        '================================
                       
        dwfnCallBack = CODEPTR(lineCallbackFunc) ' Pointer to Callback Function 
        '================================
                              
    'N.B. You should pass the pointer to lineCallbackFunc in lineInitializeEx and 0 in lineOpen.
    ' the dwCallbackInstance parameter is not a pointer to a callback function,
    ' but user-instance data. Apparently, the VB code is using it to pass a
    ' pointer to a class and then doing some tweaking to be able to call the
    ' members of the class using a dotted syntax.
    
        RetVal = lineOpen( hLineApp, _     ' 
                                Dev, _     ' DWORD dwDeviceID
                              hLine, _     ' LPHLINE lphLine - line handle for the corresponding opened line device
            TapiLine(Dev).NegAPIver, _     ' DWORD dwAPIVersion
                            BYVAL 0, _     ' DWORD dwExtVersion
                            BYVAL 0, _     ' DWORD_PTR dwCallbackInstance - User Instance Data
                         privileges, _     ' DWORD dwPrivileges
                         mediamodes, _     ' DWORD dwMediaModes
                            BYVAL 0& )     ' LPLINECALLPARAMS const lpCallParams, Usually set to NULL
        '================================
    
        IF RetVal < 0 THEN ' Zero indicates success. A negative error number indicates that an error occurred
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_ALLOCATED                : FUNCTION = "the line cannot be opened, serial port may be in use"
            CASE %LINEERR_LINEMAPPERFAILED         : FUNCTION = "no lines found matching requirements specified in lpCallParams"
            CASE %LINEERR_BADDEVICEID              : FUNCTION = "the device id is incorrect"
            CASE %LINEERR_NODRIVER                 : FUNCTION = "the driver was not found"
            CASE %LINEERR_INCOMPATIBLEAPIVERSION   : FUNCTION = "the API version is incompatible"
            CASE %LINEERR_NOMEM                    : FUNCTION = "not enough memory is available"
            CASE %LINEERR_OPERATIONFAILED          : FUNCTION = "the operation failed"      
            CASE %LINEERR_INVALAPPHANDLE           : FUNCTION = "the application handle is invalid"
            CASE %LINEERR_RESOURCEUNAVAIL          : FUNCTION = "he resource is unavailable"
            CASE %LINEERR_INVALMEDIAMODE           : FUNCTION = "the Media Mode is invalid"
            CASE %LINEERR_STRUCTURETOOSMALL        : FUNCTION = "the structure is too small"
            CASE %LINEERR_INVALPOINTER             : FUNCTION = "the pointer is invalid"
            CASE %LINEERR_UNINITIALIZED            : FUNCTION = "Lthe parameter is uninitialized"
            CASE %LINEERR_INVALPRIVSELECT          : FUNCTION = "the Priviledges are invalid"
            CASE %LINEERR_REINIT                   : FUNCTION = "the application attempted to initialize TAPI twice"  
            CASE %LINEERR_NODEVICE                 : FUNCTION = "the device was not found"
            CASE %LINEERR_OPERATIONUNAVAIL         : FUNCTION = "the operation is unavailable"
            CASE ELSE                              : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
        END IF ' PRINT #hDbg, "lineopen() RetVal="+STR$(RetVal)+"(Zero indicates success), TAPIver="+STR$(TapiLine(Dev).NegAPIver) 
        '================================
    
    END FUNCTION  
                
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
    FUNCTION ProcessCanonical( hLineApp AS LONG, Dev AS LONG ) AS STRING  ' hLine is GLOBAL
    'A common practice is that phone numbers are stored in canonical format,
    'which includes international the dialing code, area code, and so forth. An
    'actual call may use a modified form of this number depending on current
    'location, local or long distance call, and so forth. Therefore, the
    'initial phone number should be translated into a dialable form. To proceed
    'with this task, you need to call lineTranslateAddress. Similar to
    'lineGetDevCaps, you might be required to call this function several times
    'until a correctly sized memory block is passed to keep its output.
                        
    'the canonical address format is: 
    ' + Country/RegionCode ( AreaCode ) SubscriberNumber  
    'For example, this is how you would enter a US number in canonical address format: 
    '+1 (425) 555-0100 
    
      LOCAL RetVal, NumElem AS LONG  
      LOCAL TrnsAdd() AS LINETRANSLATEOUTPUT
                                     
                        
        FUNCTION = "" ' no problems  
        ShowText "Processing Canonical number" 
        IF TapiLine(Dev).NegAPIver = 0 THEN  ' not found in API negotiation 
          FUNCTION = "This Device cannot be found" 
          EXIT FUNCTION
        END IF 
        '================================ 
                  
        'LONG WINAPI lineTranslateAddress(  
        'HLINEAPP hLineApp ,   
        'DWORD dwDeviceID ,   
        'DWORD dwAPIVersion ,   
        'LPCSTR lpszAddressIn ,   
        'DWORD dwCard ,   
        'DWORD dwTranslateOptions ,   
        'LPLINETRANSLATEOUTPUT lpTranslateOutput
        NumElem = 1 ' Starting memory size
        DIM TrnsAdd(NumElem-1)  ' First attempt
        TrnsAdd(0).dwTotalSize = SIZEOF(LINETRANSLATEOUTPUT) * NumElem ' Size of the UDT 
        DO
          RetVal = lineTranslateAddress( hLineApp, Dev, TapiLine(Dev).NegAPIver, TapiLine(Dev).zNumToDial, 0, 0, TrnsAdd(0) ) ' Translate 
          IF CDWD(RetVal) = %LINEERR_STRUCTURETOOSMALL OR TrnsAdd(0).dwTotalSize < TrnsAdd(0).dwNeededSize  THEN ' increase buffer size
          'PRINT #hDbg, STR$(Dev) + ", NumElem=" + STR$(NumElem) + ",  TotalSize=" + STR$(TrnsAdd(0).dwTotalSize) + ",  NeededSize=" + STR$(TrnsAdd(0).dwNeededSize) 
            INCR NumElem 
            IF NumElem > 20 THEN  ' Something else is wrong 
              FUNCTION = "Memory increased x"+STR$(NumElem)+" and still not big enough for TrnsAdd!"
              EXIT FUNCTION
            END IF ' 
            REDIM TrnsAdd(NumElem-1) ' assign more memory 
            TrnsAdd(0).dwTotalSize = SIZEOF(LINETRANSLATEOUTPUT) * NumElem
          ELSE ' PRINT #hDbg, STR$(Dev) + ", NumElem=" + STR$(NumElem) + ",  TotalSize=" + STR$(TrnsAdd(0).dwTotalSize) + ",  NeededSize=" + STR$(TrnsAdd(0).dwNeededSize) 
            EXIT LOOP  
          END IF
        LOOP
        '================================  
                
        IF RetVal <> 0 THEN 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_BADDEVICEID            : FUNCTION = "the device id is incorrect"
            CASE %LINEERR_INVALPOINTER           : FUNCTION = "the pointer is invalid"
            CASE %LINEERR_INCOMPATIBLEAPIVERSION : FUNCTION = "the API version is incompatible"
            CASE %LINEERR_NODRIVER               : FUNCTION = "the driver was not found"
            CASE %LINEERR_INIFILECORRUPT         : FUNCTION = "the INI file is corrupted"
            CASE %LINEERR_NOMEM                  : FUNCTION = "not enough memory is available"   
            CASE %LINEERR_INVALADDRESS           : FUNCTION = "the address is invalid"
            CASE %LINEERR_OPERATIONFAILED        : FUNCTION = "the operation failed"
            CASE %LINEERR_INVALAPPHANDLE         : FUNCTION = "the application handle is invalid"
            CASE %LINEERR_RESOURCEUNAVAIL        : FUNCTION = "the resource is unavailable"
            CASE %LINEERR_INVALCARD              : FUNCTION = "the card is invalid"
            CASE %LINEERR_STRUCTURETOOSMALL      : FUNCTION = "the structure is too small"
            CASE %LINEERR_INVALPARAM             : FUNCTION = "the parameter is invalid"
            CASE ELSE                            : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
          EXIT FUNCTION
        END IF  
        '================================
                
        'store UDT info in class local variables   
        TapiLine(Dev).zDialableString        = GetTAPIStructString(VARPTR(TrnsAdd(0)), TrnsAdd(0).dwDialableStringOffset,    TrnsAdd(0).dwDialableStringSize)
    ' the output is always a null-terminated ASCII string (NULL is accounted for in Size). 
    ' Ancillary fields such as name and subaddress are included in this output string if they 
    ' were in the input string. This string may contain private data such as calling card numbers.
    ' It should not be displayed to the user, to prevent inadvertent visibility to unauthorized persons. 
        TapiLine(Dev).zDisplayableString     = GetTAPIStructString(VARPTR(TrnsAdd(0)), TrnsAdd(0).dwDisplayableStringOffset, TrnsAdd(0).dwDisplayableStringSize)
    ' Contain the translated output that can be displayed to the user for confirmation. It is identical to
    ' DialableString, except that calling card digits are replaced with the friendly name of the card enclosed 
    ' within bracket characters, and ancillary fields such as name and subaddress are removed. It should 
    ' normally be safe to display this string in call-status dialog boxes without exposing private data to 
    ' unauthorized persons. This data is also appropriate to include in call logs. ]
        TapiLine(Dev).CurrentCountry         = TrnsAdd(0).dwCurrentCountry
    ' Country/region code configured in CurrentLocation. This value may be used to control the 
    ' display by the application of certain user interface elements, for local call progress tone detection, 
    ' and for other purposes. 
        TapiLine(Dev).DestCountry            = TrnsAdd(0).dwDestCountry  
    ' Destination country/region code of the translated address. This value may be passed 
    ' to the dwCountryCode parameter of lineMakeCall and other dialing functions (so that 
    ' the call progress tones of the destination country/region such as a busy signal are 
    ' properly detected). This field is set to zero if the destination address passed to the 
    ' lineTranslateAddress function is not in canonical format.
        TapiLine(Dev).TranslateResults       = TrnsAdd(0).dwTranslateResults 
    ' Value that indicates the data derived from the translation process, which may assist 
    ' the application in presenting user-interface elements 
        '================================   
                               
                   
        SELECT CASE TapiLine(Dev).TranslateResults
          CASE 0 : TapiLine(Dev).TranslateDefn = "input string was not in valid canonical form" ' This function has essentailly failed 
          CASE %LINETRANSLATERESULT_CANONICAL     : TapiLine(Dev).TranslateDefn = "input string was in valid canonical form"
          CASE %LINETRANSLATERESULT_INTERNATIONAL : TapiLine(Dev).TranslateDefn = "call treated as an international call"
          CASE %LINETRANSLATERESULT_LONGDISTANCE  : TapiLine(Dev).TranslateDefn = "area code is different from current location"
          CASE %LINETRANSLATERESULT_LOCAL         : TapiLine(Dev).TranslateDefn = "Local Call"
          CASE %LINETRANSLATERESULT_INTOLLLIST    : TapiLine(Dev).TranslateDefn = "call is being dialed as long distance"
          CASE %LINETRANSLATERESULT_NOTINTOLLLIST : TapiLine(Dev).TranslateDefn = "prefix not in TollPrefixList"
          CASE %LINETRANSLATERESULT_DIALBILLING   : TapiLine(Dev).TranslateDefn = "returned address contains a $"
          CASE %LINETRANSLATERESULT_DIALQUIET     : TapiLine(Dev).TranslateDefn = "returned address contains a @"
          CASE %LINETRANSLATERESULT_DIALDIALTONE  : TapiLine(Dev).TranslateDefn = "returned address contains a W"
          CASE %LINETRANSLATERESULT_DIALPROMPT    : TapiLine(Dev).TranslateDefn = "returned address contains a ?"
          CASE %LINETRANSLATERESULT_VOICEDETECT   : TapiLine(Dev).TranslateDefn = "LPause until a voice prompt is detected"
          CASE ELSE                               : TapiLine(Dev).TranslateDefn = "Unknown Translate Result Code=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
        END SELECT
        '================================ 
    
    'PRINT #hDbg,  "Dev=" + STR$(Dev) + ", zNumToDial=" + TRIM$(TapiLine(Dev).zNumToDial) 
    'PRINT #hDbg,  "TranslateResults=" + STR$(TapiLine(Dev).TranslateResults) + _ 
    '              ", Defn=" + TapiLine(Dev).TranslateDefn     
    'PRINT #hDbg,  "zDialableString=" + TRIM$(TapiLine(Dev).zDialableString) + _
    '              ", DisplayableString=" + TRIM$(TapiLine(Dev).zDisplayableString)
    'PRINT #hDbg,  ", CurrentCountry=" + STR$(TapiLine(Dev).CurrentCountry) + _
    '              ", DestCountry=" + STR$(TapiLine(Dev).DestCountry)
    
    END FUNCTION  
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION MakeCallAsynch( zNumToDial AS ASCIIZ*%MAX_PATH ) AS STRING ' hCall, hLine are GLOBAL, zDialableString is in the TYPE
                     
    'lineMakeCall operates asynchronously; in other words, it will return
    'control before dialing is completed. the application will receive
    'notifications on different stages of this process via supported a callback
    'function. you can look at the CeDialer sample in the SDK for more details.
      LOCAL RetVal AS LONG  
                   
        FUNCTION = "" ' no problems 
                          
        ShowText "Dialing: " + TRIM$(zNumToDial)
        IF hLine = 0 THEN  
            FUNCTION = "Line not open"
            EXIT FUNCTION   
        END IF  
        '================================
                                                                             
        'if zNumToDial = "" then it will just get a dial tone  
        RetVal = lineMakeCall(hLine, hCall, zNumToDial, 0&, BYVAL 0&) 'dial a number  
    
    ' Returns a positive request identifier if the function is completed asynchronously, or a negative 
    ' error number if an error occurs. the dwParam2 parameter of the corresponding LINE_REPLY 
    ' message is zero if the function succeeds or it is a negative error number if an error occurs. 
    ' the following table shows the return values for this function. 
                           
    ' After lineMakeCall returns a success reply message (>0) to the application, a LINE_CALLSTATE message 
    ' is sent to the application to indicate the current state of the call. This state is not necessarily 
    ' LINECALLSTATE_DIALTONE.
    ' PRINT #hDbg, "lineMakeCall() handle="+STR$(RetVal)+", hLine="+STR$(hLine)+", NumToDial="+TRIM$(zNumToDial)
                         
        IF RetVal > 0 THEN
            'now placing call - completion will be signalled by a LINE_REPLY event in the callback
            'store positive request identifier in class member variable for use in the callback handler
            RequestingCall = RetVal 
        ELSE ' RetVal < 0 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_ADDRESSBLOCKED     : FUNCTION = "the address is blocked"
            CASE %LINEERR_INVALLINEHANDLE    : FUNCTION = "the line handle is invalid"
            CASE %LINEERR_BEARERMODEUNAVAIL  : FUNCTION = "bearer mode specified not valid/available" ' in LINECALLPARAMS 
            CASE %LINEERR_INVALLINESTATE     : FUNCTION = "the line is not in a valid state"
            CASE %LINEERR_CALLUNAVAIL        : FUNCTION = "the call is unavailable"
            CASE %LINEERR_INVALMEDIAMODE     : FUNCTION = "the media mode is invalid"   
            CASE %LINEERR_DIALBILLING        : FUNCTION = "Billing control chars cannot be processed by service provider"
            CASE %LINEERR_INVALPARAM         : FUNCTION = "the parameters are invalid"
            CASE %LINEERR_DIALDIALTONE       : FUNCTION = "Dialing control chars cannot be processed by service provider"
            CASE %LINEERR_INVALPOINTER       : FUNCTION = "the pointer is invalid"
            CASE %LINEERR_DIALPROMPT         : FUNCTION = "Prompt control chars cannot be processed by service provider"
            CASE %LINEERR_INVALRATE          : FUNCTION = "the rate is invalid"
            CASE %LINEERR_DIALQUIET          : FUNCTION = "Quiet control chars cannot be processed by service provider"
            CASE %LINEERR_NOMEM              : FUNCTION = "Out of memory"      
            CASE %LINEERR_INUSE              : FUNCTION = "the line is in use"
            CASE %LINEERR_OPERATIONFAILED    : FUNCTION = "the operation failed"
            CASE %LINEERR_INVALADDRESS       : FUNCTION = "the address is invalid"
            CASE %LINEERR_OPERATIONUNAVAIL   : FUNCTION = "the operation is unavailable"
            CASE %LINEERR_INVALADDRESSID     : FUNCTION = "the address id is invalid"
            CASE %LINEERR_RATEUNAVAIL        : FUNCTION = "the rate is unavailable"
            CASE %LINEERR_INVALADDRESSMODE   : FUNCTION = "the address mode is invalid"
            CASE %LINEERR_RESOURCEUNAVAIL    : FUNCTION = "the resource is unavailable"  
            CASE %LINEERR_INVALBEARERMODE    : FUNCTION = "the bearer mode is invalid"
            CASE %LINEERR_STRUCTURETOOSMALL  : FUNCTION = "the structure is too small"
            CASE %LINEERR_INVALCALLPARAMS    : FUNCTION = "Invalid parameters used for this call"
            CASE %LINEERR_UNINITIALIZED      : FUNCTION = "the parameter is uninitialized"
            CASE %LINEERR_INVALCOUNTRYCODE   : FUNCTION = "the country/region code provided was invalid"
            CASE %LINEERR_USERUSERINFOTOOBIG : FUNCTION = "the users information is too large"
            CASE ELSE                        : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
        END IF  
        '================================
        
        'now placing call - completion will be signalled by a LINE_REPLY event in the callback
        'store positive request identifier in class member variable for use in the callback handler
        
    END FUNCTION   
                  
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION DropCallAsynch( ) AS STRING  ' hCall is global
                       
    'Finally, after all requested operations are performed on the line device,
    'you should close it and release all allocated resources. You also should
    'clean up the resources in response to errors that occurred. If you have
    'made a call, you should use the following two APIs:
    'LONG lineDrop( HCALL hCall, LPCTSTR lpsUserUserInfo, DWORD dwSize );
    'LONG lineDeallocateCall( HCALL hCall );
    
      LOCAL RetVal AS LONG 
      LOCAL zTemp AS ASCIIZ*255 
                       
        FUNCTION = "" ' no problems 
        ShowText "Dropping Call"    
        If hCall = 0 Then
            FUNCTION = "No Call to Drop"
            EXIT FUNCTION 
        END IF  
        '================================
        
        RetVal = lineDrop( hCall, zTemp, 0& ) ' 
        ' Returns a positive request identifier if the function is completed asynchronously
        ' or a negative error number if an error occurs.
                                
        IF RetVal > 0 THEN ' dropping call
          DroppingCall = RetVal 
        ELSE ' RetVal < 0 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_INVALCALLHANDLE      : FUNCTION = "the Call handle is invalid"
            CASE %LINEERR_OPERATIONUNAVAIL     : FUNCTION = "the operation is unavailable"
            CASE %LINEERR_NOMEM                : FUNCTION = "Out of memory"
            CASE %LINEERR_OPERATIONFAILED      : FUNCTION = "the operation failed"
            CASE %LINEERR_NOTOWNER             : FUNCTION = "This application is not the owner of the call"
            CASE %LINEERR_RESOURCEUNAVAIL      : FUNCTION = "the resource is unavailable"
            CASE %LINEERR_INVALPOINTER         : FUNCTION = "the pointer is invalid"
            CASE %LINEERR_USERUSERINFOTOOBIG   : FUNCTION = "the users information is too large"      
            CASE %LINEERR_INVALCALLSTATE       : FUNCTION = "Invalid call state"
            CASE %LINEERR_UNINITIALIZED        : FUNCTION = "the parameter is uninitialized"
            CASE ELSE                          : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
        END IF   
        '================================
          
    END FUNCTION  
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION DeallocateCall( ) AS STRING ' hCall is global     
     
    ' the deallocation does not affect the call state of the physical call. It does, however, 
    ' release internal resources related to the call
                
      LOCAL RetVal AS LONG 
                     
        FUNCTION = "" ' no problems 
             
        ShowText "Deallocating Call" 
        CALL lineDeallocateCall( hCall ) 
        IF RetVal < 0 THEN 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_INVALCALLHANDLE   : FUNCTION = "the Call Handle is invalid"
            CASE %LINEERR_OPERATIONFAILED   : FUNCTION = "the operation failed"
            CASE %LINEERR_INVALCALLSTATE    : FUNCTION = "Invalid call state"
            CASE %LINEERR_RESOURCEUNAVAIL   : FUNCTION = "the resource is unavailable"
            CASE %LINEERR_NOMEM             : FUNCTION = "not enough memory is available"
            CASE %LINEERR_UNINITIALIZED     : FUNCTION = "the parameter is uninitialized"
            CASE ELSE                       : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
          EXIT FUNCTION
        END IF  
        '================================  
        hCall = 0
    END FUNCTION  
                   
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION CloseLine( ) AS STRING ' hLine is GLOBAL
                        
    ' Handle to the open line device to be closed. After the line has been successfully closed, 
    ' this handle is no longer valid. 
    ' If an application calls lineClose while it still has active calls on the opened line, the application's 
    ' ownership of these calls is revoked. If the application was the sole owner of these calls, the calls 
    ' are dropped as well. It is good programming practice for an application to dispose of the calls it 
    ' owns on an opened line by explicitly relinquishing ownership and/or by dropping these calls prior 
    ' to closing the line.
      LOCAL RetVal AS LONG  
                             
        FUNCTION = "" ' no problems 
        ShowText "Closing Line" 
        '================================  
        IF hLine = 0 THEN  
            FUNCTION = "No Line to Close"
            EXIT FUNCTION 
        END IF    
        '================================      
        
        RetVal = lineClose( hLine )
                          
        IF RetVal < 0 THEN 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_INVALLINEHANDLE   : FUNCTION = "the Line Handle is Invalid"
            CASE %LINEERR_RESOURCEUNAVAIL   : FUNCTION = "the resource is unavailable"
            CASE %LINEERR_NOMEM             : FUNCTION = "not enough memory is available"
            CASE %LINEERR_UNINITIALIZED     : FUNCTION = "the parameter is uninitialized"
            CASE %LINEERR_OPERATIONFAILED   : FUNCTION = "the operation failed"
            CASE %LINEERR_OPERATIONUNAVAIL  : FUNCTION = "the operation is unavailable"
            CASE ELSE                       : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
          EXIT FUNCTION
        END IF 
        '================================  
        hLine = 0 ' Handle freed up
    END FUNCTION   
         
                
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION ShutdownLine( ) AS STRING  ' hLine is GLOBAL
                   
    ' the lineShutdown function shuts down the application's usage of the line abstraction of the API.
    ' If this function is called when the application has lines open or calls active, the call handles are 
    ' deleted and TAPI automatically performs the equivalent of a lineClose on each open line. However, 
    ' it is recommended that applications explicitly close all open lines before invoking lineShutdown.
    ' If shutdown is performed while asynchronous requests are outstanding, those requests are canceled.
      LOCAL RetVal AS LONG  
                           
        FUNCTION = "" ' no problems 
                                     
        ShowText "Shutting Down Line" 
        IF hLine = 0 THEN  
            FUNCTION = "No Line to Close"
            EXIT FUNCTION 
        END IF  
        '================================  PRINT #hDbg, "hLine=" + STR$(hLine) 
        RetVal = lineShutdown( hLine )
                          
        IF RetVal < 0 THEN 
          SELECT CASE CDWD(RetVal)
            CASE %LINEERR_INVALAPPHANDLE    : FUNCTION = "the application handle is invalid"
            CASE %LINEERR_NOMEM             : FUNCTION = "not enough memory is available"
            CASE %LINEERR_RESOURCEUNAVAIL   : FUNCTION = "the resource is unavailable"
            CASE %LINEERR_UNINITIALIZED     : FUNCTION = "the parameter is uninitialized"
            CASE ELSE                       : FUNCTION = "Unknown Return Value=" + STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT 
        END IF 
        '================================
    END FUNCTION 
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION ShowText( sTxt AS STRING ) AS LONG
                  
    'PRINT #hDbg, sTxt ' For debugging 
    'PRINT #hDbg, ""
              
        sTxt = sTxt + $CRLF  
        CONTROL SEND hDlg, 401, %EM_REPLACESEL,  0, STRPTR(sTxt) ' Add text to the end
      FUNCTION = 1
    END FUNCTION  
                      
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION lineCallbackFunc( BYVAL hDevice            AS DWORD, _   ' Handle callbacks here
                               BYVAL dwMsg              AS DWORD, _   ' the callback instance supplied when opening the call's line 
                               BYVAL dwCallbackInstance AS DWORD, _   ' user-instance value
                               BYVAL dwParam1           AS DWORD, _   ' Request Identifier Code
                               BYVAL dwParam2           AS DWORD, _   ' Reply Code 
                               BYVAL dwParam3           AS DWORD) AS LONG 
                                                             
    ' dwCallbackInstance is a user-instance value that you can pass in the lineOpen function and that 
    ' the VB programmer is using to pass a pointer to his class and then converting to an object variable 
    ' to be able to use the dotted syntax. This parameter can be any dword value that you will find useful or 0.
    msgbox "inside callback"   
                           
    ' the Line Callback function is used by TAPI to inform your application about 
    ' various events that happen during the TAPI session. 
    ' 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.           
          
    ' LINE_REPLY messages:       
    ' Functions that operate asynchronously return a positive request identifier value to the application. 
    ' This request identifier is returned with the reply message to identify the request that was completed. 
    ' the other parameter for the LINE_REPLY message carries the success or failure indication. 
    ' Possible errors are the same as those defined by the corresponding function. 
    ' In some cases, an application may fail to receive the LINE_REPLY message corresponding to 
    ' a call to an asynchronous function. This occurs if the corresponding call handle is deallocated 
    ' before the message has been received.    
    ' Note:   When an application invokes any asynchronous operation that writes data back into 
    ' application memory, the application must keep that memory available for writing until a 
    ' LINE_REPLY or LINE_GATHERDIGITS message is received.
     
                
    ' If hWnd is NULL, GetMessage retrieves messages for any window that belongs to the 
    ' calling thread and thread messages posted to the calling thread by means of PostThreadMessage.
      STATIC sTemp AS STRING ' PRINT #hDbg, "Entering LineProcHandler"   
        SELECT CASE dwMsg 
            CASE %LINE_REPLY ' Functions that operate asynchronously return a positive request identifier value to the application
                ' PRINT #hDbg, "%LINE_REPLY: dwParam1=" + STR$(dwParam1) + ", dwParam2=" + STR$(dwParam2) + ", dwParam3=" + STR$(dwParam3) 
                IF dwParam1 = RequestingCall THEN ' the request identifier for which this is the reply
                    RequestingCall = -1 ' Requester from lineMakeCall() don't need ID anymore - it matched
                    IF dwParam2 = 0 THEN ' Zero indicates success, negative number indicates an error
                      ShowText "TAPI MSG: LINE_REPLY - DIALING"
                    ELSE ' Possible errors are the same as those defined by the corresponding function 
                      SELECT CASE dwParam2
                        CASE %LINEERR_ADDRESSBLOCKED     : sTemp = "the address is blocked"
                        CASE %LINEERR_INVALLINEHANDLE    : sTemp = "the line handle is invalid"
                        CASE %LINEERR_BEARERMODEUNAVAIL  : sTemp = "bearer mode specified not valid/available" ' in LINECALLPARAMS 
                        CASE %LINEERR_INVALLINESTATE     : sTemp = "the line is not in a valid state"
                        CASE %LINEERR_CALLUNAVAIL        : sTemp = "the call is unavailable"
                        CASE %LINEERR_INVALMEDIAMODE     : sTemp = "the media mode is invalid"   
                        CASE %LINEERR_DIALBILLING        : sTemp = "Billing control chars cannot be processed by service provider"
                        CASE %LINEERR_INVALPARAM         : sTemp = "the parameters are invalid"
                        CASE %LINEERR_DIALDIALTONE       : sTemp = "Dialing control chars cannot be processed by service provider"
                        CASE %LINEERR_INVALPOINTER       : sTemp = "the pointer is invalid"
                        CASE %LINEERR_DIALPROMPT         : sTemp = "Prompt control chars cannot be processed by service provider"
                        CASE %LINEERR_INVALRATE          : sTemp = "the rate is invalid"
                        CASE %LINEERR_DIALQUIET          : sTemp = "Quiet control chars cannot be processed by service provider"
                        CASE %LINEERR_NOMEM              : sTemp = "Out of memory"      
                        CASE %LINEERR_INUSE              : sTemp = "the line is in use"
                        CASE %LINEERR_OPERATIONFAILED    : sTemp = "the operation failed"
                        CASE %LINEERR_INVALADDRESS       : sTemp = "the address is invalid"
                        CASE %LINEERR_OPERATIONUNAVAIL   : sTemp = "the operation is unavailable"
                        CASE %LINEERR_INVALADDRESSID     : sTemp = "the address id is invalid"
                        CASE %LINEERR_RATEUNAVAIL        : sTemp = "the rate is unavailable"
                        CASE %LINEERR_INVALADDRESSMODE   : sTemp = "the address mode is invalid"
                        CASE %LINEERR_RESOURCEUNAVAIL    : sTemp = "the resource is unavailable"  
                        CASE %LINEERR_INVALBEARERMODE    : sTemp = "the bearer mode is invalid"
                        CASE %LINEERR_STRUCTURETOOSMALL  : sTemp = "the structure is too small"
                        CASE %LINEERR_INVALCALLPARAMS    : sTemp = "Invalid parameters used for this call"
                        CASE %LINEERR_UNINITIALIZED      : sTemp = "the parameter is uninitialized"
                        CASE %LINEERR_INVALCOUNTRYCODE   : sTemp = "the country/region code provided was invalid"
                        CASE %LINEERR_USERUSERINFOTOOBIG : sTemp = "the users information is too large"
                        CASE ELSE                        : sTemp = "Unknown Return Value=" + STR$(dwParam2) + " = &H" + HEX$(dwParam2)
                      END SELECT  
                      ShowText "TAPI MSG: LINE_REPLY - " + sTemp 
                      sTemp = CloseLine( )  
                      IF LEN(sTemp) THEN ShowText "CloseLine() Error: " + sTemp ' if it was an error make sure the line is closed 
                    END IF
                ELSEIF dwParam1 = DroppingCall THEN  ' asynch reply to lineDrop() call
                    DroppingCall = -1  ' Requester from lineDrop()
                    IF dwParam2 = 0 THEN
                      ShowText "TAPI MSG: LINE_REPLY - CALL DROPPED"  
                    ELSE ' Possible errors are the same as those defined by the corresponding function 
                      SELECT CASE dwParam2
                        CASE %LINEERR_INVALCALLHANDLE      : sTemp = "the Call handle is invalid"
                        CASE %LINEERR_OPERATIONUNAVAIL     : sTemp = "the operation is unavailable"
                        CASE %LINEERR_NOMEM                : sTemp = "Out of memory"
                        CASE %LINEERR_OPERATIONFAILED      : sTemp = "the operation failed"
                        CASE %LINEERR_NOTOWNER             : sTemp = "This application is not the owner of the call"
                        CASE %LINEERR_RESOURCEUNAVAIL      : sTemp = "the resource is unavailable"
                        CASE %LINEERR_INVALPOINTER         : sTemp = "the pointer is invalid"
                        CASE %LINEERR_USERUSERINFOTOOBIG   : sTemp = "the users information is too large"      
                        CASE %LINEERR_INVALCALLSTATE       : sTemp = "Invalid call state"
                        CASE %LINEERR_UNINITIALIZED        : sTemp = "the parameter is uninitialized"
                        CASE ELSE                          : sTemp = "Unknown Return Value=" + STR$(dwParam2) + " = &H" + HEX$(dwParam2)
                      END SELECT 
                      ShowText "TAPI MSG: LINE_REPLY - " + sTemp 
                    END IF 
                ELSE
                  ShowText "TAPI MSG: Unknown LINE_REPLY - " + STR$(dwParam1) + " = &H" + HEX$(dwParam1)
                END IF   
    
            CASE %LINE_CALLSTATE ' status of the specified call has changed
              ' PRINT #hDbg, "%LINE_CALLSTATE: dwParam1=" + STR$(dwParam1) + ", dwParam2=" + STR$(dwParam2) + ", dwParam3=" + STR$(dwParam3)  
              ' the TAPI LINE_CALLSTATE message is sent when the status of the specified call has changed. 
              ' Typically, several such messages are received during the lifetime of a call. 
              ' Applications are notified of new incoming calls with this message; the new call is in the offering state. 
              ' the application can use lineGetCallStatus to retrieve more detailed information about the current status of the call.
    msgbox "line_callstate"          
                SELECT CASE dwParam1 ' the new call state, dwParam2 ' Call-state-dependent information
                    CASE %LINECALLSTATE_DISCONNECTED ' remote party has disconnected from the call 
                        SELECT CASE dwParam2
                          CASE %LINEDISCONNECTMODE_BADADDRESS     : sTemp = "the destination address is invalid" 
                          CASE %LINEDISCONNECTMODE_BLOCKED        : sTemp = "calls from the origination address are not being accepted"
                          CASE %LINEDISCONNECTMODE_BUSY           : sTemp = "the remote users station is busy" 
                          CASE %LINEDISCONNECTMODE_CANCELLED      : sTemp = "the call was cancelled"
                          CASE %LINEDISCONNECTMODE_CONGESTION     : sTemp = "the network is congested" 
                          CASE %LINEDISCONNECTMODE_DONOTDISTURB   : sTemp = "destination has invoked the Do not Disturb feature"
                          CASE %LINEDISCONNECTMODE_FORWARDED      : sTemp = "the call was forwarded by the switch" 
                          CASE %LINEDISCONNECTMODE_INCOMPATIBLE   : sTemp = "the remote users station equipment is incompatible"
                          CASE %LINEDISCONNECTMODE_NOANSWER       : sTemp = "the remote users station does not answer" 
                          CASE %LINEDISCONNECTMODE_NODIALTONE     : sTemp = "a dial tone was not detected within a service-provider defined timeout"
                          CASE %LINEDISCONNECTMODE_NORMAL         : sTemp = "the call was terminated normally" 
                          CASE %LINEDISCONNECTMODE_NUMBERCHANGED  : sTemp = "destination number has been changed"
                          CASE %LINEDISCONNECTMODE_OUTOFORDER     : sTemp = "destination device is out of order (hardware failure)"
                          CASE %LINEDISCONNECTMODE_PICKUP         : sTemp = "the call was picked up from elsewhere" 
                          CASE %LINEDISCONNECTMODE_QOSUNAVAIL     : sTemp = "minimum quality of service could not be obtained or sustained"
                          CASE %LINEDISCONNECTMODE_REJECT         : sTemp = "the remote user has rejected the call" 
                          CASE %LINEDISCONNECTMODE_TEMPFAILURE    : sTemp = "temporary failure in the network"
                          CASE %LINEDISCONNECTMODE_UNAVAIL        : sTemp = "the reason for the disconnect is unavailable and will not become known later" 
                          CASE %LINEDISCONNECTMODE_UNKNOWN        : sTemp = "the reason for the disconnect request is unknown but may become known later" 
                          CASE %LINEDISCONNECTMODE_UNREACHABLE    : sTemp = "the remote user could not be reached" 
                        END SELECT 
                        ShowText "TAPI MSG: LINECALLSTATE_DISCONNECTED - " + sTemp 
                                   
                    CASE %LINECALLSTATE_IDLE ' no call exists - the line is idle 
                        ' the call exists but has not been connected. No activity exists on the call, which means that no call
                        ' is currently active. A call can never transition out of the idle state. 
                        ShowText "TAPI MSG: LINECALLSTATE_IDLE"
                        IF hCall <> 0 THEN  ' Free up the resources
                          sTemp = DeallocateCall() ' Line Go Idle 
                          IF LEN(sTemp) THEN ShowText "DeallocateCall() Error: " + sTemp : EXIT FUNCTION
                        END IF
                        IF hLine <> 0 THEN  ' Free up the line
                          sTemp = CloseLine()
                          IF LEN(sTemp) THEN ShowText "CloseLine() Error: " + sTemp : EXIT FUNCTION ' if it was an error make sure the line is closed 
                        END IF
                        CONTROL DISABLE hDlg, 307 ' Disable Hang Up 
                        CONTROL ENABLE  hDlg, 305 ' Enable Dial 
    
                    CASE %LINECALLSTATE_CONNECTED ' dwParam2 details about connected mode - LINECONNECTEDMODE_ constants  
                        SELECT CASE dwParam2 ' If the call state mode is ZERO, the application should assume that the value is "active"
                          CASE 0                                  : sTemp = "the call is ASSUMED to be connected"
                          CASE %LINEDISCONNECTMODE_BADADDRESS     : sTemp = "the destination address is invalid" 
                          CASE %LINECONNECTEDMODE_ACTIVE          : sTemp = "the call IS connected at the current station" 
                          CASE %LINECONNECTEDMODE_ACTIVEHELD      : sTemp = "remote party has placed the call on hold"
                          CASE %LINECONNECTEDMODE_CONFIRMED       : sTemp = "service provider received notification that the call is connected"
                          CASE %LINECONNECTEDMODE_INACTIVE        : sTemp = "the current station is not a participant in the call"
                          CASE %LINECONNECTEDMODE_INACTIVEHELD    : sTemp = "the remote party has placed the call on hold" 
                        END SELECT 
                        ShowText "TAPI MSG: LINECALLSTATE_CONNECTED - " + sTemp 'RaiseEvent Connected
                                           
                    CASE %LINECALLSTATE_BUSY ' dwParam2 details about busy mode - LINEBUSYMODE_ constants
                        SELECT CASE dwParam2
                          CASE %LINEBUSYMODE_STATION : sTemp = "the called party's station is busy"
                          CASE %LINEBUSYMODE_TRUNK   : sTemp = "trunk or circuit is busy"
                          CASE %LINEBUSYMODE_UNKNOWN : sTemp = "busy signal's specific mode is currently unknown"
                          CASE %LINEBUSYMODE_UNAVAIL : sTemp = "signal's specific mode is unavailable"
                        END SELECT 
                        ShowText "TAPI MSG: LINECALLSTATE_BUSY - " + sTemp
                    
                    CASE %LINECALLSTATE_DIALTONE ' dwParam2 details about dial tone mode - LINEDIALTONEMODE_ constants  
                        SELECT CASE dwParam2   
                          CASE %LINEDIALTONEMODE_EXTERNAL  : sTemp = "This is an external (public network) dial tone" 
                          CASE %LINEDIALTONEMODE_INTERNAL  : sTemp = "This is an internal dial tone, as within a PBX"
                          CASE %LINEDIALTONEMODE_NORMAL    : sTemp = "This is a normal dial tone, which typically is a continuous tone" 
                          CASE %LINEDIALTONEMODE_SPECIAL   : sTemp = "This is a special dial tone"
                          CASE %LINEDIALTONEMODE_UNAVAIL   : sTemp = "the dial tone mode is unavailable and will not become known" 
                          CASE %LINEDIALTONEMODE_UNKNOWN   : sTemp = "the dial tone mode is not currently known but may become known later" 
                        END SELECT 
                        ShowText "TAPI MSG: LINECALLSTATE_DIALTONE - " + sTemp 'switch is ready to receive a dialed number
                    
                    CASE %LINECALLSTATE_SPECIALINFO ' dwParam2 details about special information mode - LINESPECIALINFO_ constants  
                        SELECT CASE dwParam2   
                          CASE %LINESPECIALINFO_CUSTIRREG : sTemp = "a vacant number, AIS, Centrex number change and nonworking station..." 
                          CASE %LINESPECIALINFO_NOCIRCUIT : sTemp = "no circuit or an emergency announcement (trunk blockage category)" 
                          CASE %LINESPECIALINFO_REORDER   : sTemp = "reorder announcement (equipment irregularity category)"
                          CASE %LINESPECIALINFO_UNAVAIL   : sTemp = "Specifics are unavailable and will not become known" 
                          CASE %LINESPECIALINFO_UNKNOWN   : sTemp = "Specifics are currently unknown but may become known later"
                        END SELECT  
                        ShowText "TAPI MSG: LINECALLSTATE_SPECIALINFO - " + sTemp 'network error occured
                              
                    CASE %LINECALLSTATE_OFFERING ' dwParam2 details about connected mode - LINEOFFERINGMODE_ constants
    msgbox "offering"
                        SELECT CASE dwParam2 ' describe different substates OF an offering CALL  
                          CASE %LINEOFFERINGMODE_ACTIVE    : sTemp = "call is alerting at the current station"
                          CASE %LINEOFFERINGMODE_INACTIVE  : sTemp = "Indicates that the call is being offered at more than one station"
                        END SELECT 
                        ShowText "TAPI MSG: LINECALLSTATE_OFFERING - " + sTemp 
                                       
                    CASE %LINECALLSTATE_RINGBACK  
                        ' the station to be called has been reached, and the destination's switch is generating a ring tone 
                        ' back to the originator. A ringback means that the destination address is being alerted to the call.
                        ShowText "TAPI MSG: LINECALLSTATE_RINGBACK" 'the other station has been reached and is being alerted (ringing)
                    
                    CASE %LINECALLSTATE_DIALING ' the originator is dialing digits on the call. the dialed digits are collected by the switch.
                        ShowText "TAPI MSG: LINECALLSTATE_DIALING"
                    
                    CASE %LINECALLSTATE_PROCEEDING '  
                      ' Dialing has completed and the call is proceeding through the switch or telephone network. 
                      ' This occurs after dialing is complete and before the call reaches the dialed party, 
                      ' as indicated by ringback, busy, or answer. 
                        ShowText "TAPI MSG: LINECALLSTATE_PROCEEDING"   
                    CASE ELSE ' an unknown message is sent only if lineCompleteTransfer causes calls to be resolved into a three-way conference
                        ShowText "TAPI MSG: Unknown LINE_CALLSTATE - " + STR$(dwParam1) + " = &H" + HEX$(dwParam1)
                END SELECT  
            CASE %LINE_ADDRESSSTATE        : ShowText "TAPI MSG: LINE_ADDRESSSTATE, the status of an address changes on a line that is currently open"  
            CASE %LINE_APPNEWCALL          : ShowText "TAPI MSG: LINE_APPNEWCALL, a new call handle has been spontaneously created on its behalf"
    '       CASE %LINE_APPNEWCALLHUB       : ShowText "TAPI MSG: LINE_APPNEWCALLHUB, a new call hub has been created"
            CASE %LINE_CALLINFO            : ShowText "TAPI MSG: LINE_CALLINFO, call information about the specified call has changed"
    '       CASE %LINE_CALLHUBCLOSE        : ShowText "TAPI MSG: LINE_CALLHUBCLOSE, a call hub has been closed" 
            CASE %LINE_CLOSE               : ShowText "TAPI MSG: LINE_CLOSE, the specified line device has been forcibly closed"
            CASE %LINE_CREATE              : ShowText "TAPI MSG: LINE_CREATE, creation of a new line device"
            CASE %LINE_DEVSPECIFIC         : ShowText "TAPI MSG: LINE_DEVSPECIFIC, device-specific events occurring on a line, address, or call"
    '       CASE %LINE_DEVSPECIFICEX       : ShowText "TAPI MSG: LINE_DEVSPECIFICEX, device-specific events occurring on a line, address, or call"
            CASE %LINE_DEVSPECIFICFEATURE  : ShowText "TAPI MSG: LINE_DEVSPECIFICFEATURE, device-specific events occurring on a line, address, or call"
            CASE %LINE_GATHERDIGITS        : ShowText "TAPI MSG: LINE_GATHERDIGITS, current buffered digit-gathering request has terminated or is canceled" 
            CASE %LINE_GENERATE            : ShowText "TAPI MSG: LINE_GENERATE, current digit or tone generation has terminated"
            CASE %LINE_LINEDEVSTATE        : ShowText "TAPI MSG: LINE_LINEDEVSTATE, the state of a line device has changed"
            CASE %LINE_MONITORDIGITS       : ShowText "TAPI MSG: LINE_MONITORDIGITS, a digit is detected"
            CASE %LINE_MONITORMEDIA        : ShowText "TAPI MSG: LINE_MONITORMEDIA, a change in the calls media type is detected"
            CASE %LINE_MONITORTONE         : ShowText "TAPI MSG: LINE_MONITORTONE, a tone is detected"
            CASE %LINE_REMOVE              : ShowText "TAPI MSG: LINE_REMOVE, removal of a line device"
            CASE %LINE_REQUEST             : ShowText "TAPI MSG: LINE_REQUEST, the arrival OF a NEW request FROM another application" 
            CASE ELSE                      : ShowText "TAPI MSG: Unknown Message - " + STR$(dwMsg) + " = &H" + HEX$(dwMsg)  
        END SELECT
        msgbox "end callback"
    END FUNCTION
                   
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION PaintDevIcon( BYVAL Dev AS LONG, hIcon AS LONG ) AS STRING
                           
      LOCAL zTemp AS ASCIIZ*255   
      LOCAL RetVal AS LONG    
          
    ' LONG WINAPI lineGetIcon(  DWORD dwDeviceID ,   LPCSTR lpszDeviceClass,   LPHICON lphIcon )
                       
    'dwDeviceID 
    'Identifier of the line device whose icon is requested. 
    'lpszDeviceClass 
    'Pointer to a null-terminated string that identifies a device class name. This device class allows the 
    'application to select a specific sub-icon applicable to that device class. This parameter is optional 
    'and can be left NULL or empty, in which case the highest-level icon associated with the line device 
    'rather than a specified media stream device would be selected. 
    'lphIcon 
    'Pointer to a memory location in which the handle to the icon is returned. 
                               
        FUNCTION = "" ' no problems 
                                
        zTemp = "tapi/line"  ' Substitute Generic icon if none is available
        RetVal = lineGetIcon( TapiLine(Dev).CurrentLineID, zTemp, hIcon )
        IF RetVal <> 0 THEN            
          SELECT CASE CDWD(RetVal) 
            CASE %LINEERR_BADDEVICEID            : FUNCTION = "Bad device id provided" 
            CASE %LINEERR_OPERATIONFAILED        : FUNCTION = "the operation failed"   
            CASE %LINEERR_INVALPOINTER           : FUNCTION = "Invalid pointer" 
            CASE %LINEERR_RESOURCEUNAVAIL        : FUNCTION = "the resource is unavailable" 
            CASE %LINEERR_INVALDEVICECLASS       : FUNCTION = "Invalid Device Class"
            CASE %LINEERR_UNINITIALIZED          : FUNCTION = "the parameter is uninitialized"
            CASE %LINEERR_NOMEM                  : FUNCTION = "No memory is available" 
            CASE %LINEERR_NODEVICE               : FUNCTION = "No device was found"  
            CASE %LINEERR_OPERATIONUNAVAIL       : FUNCTION = "Operation Unavailable"  
            CASE ELSE                            : FUNCTION = "Undefined Error"+STR$(RetVal) + " = &H" + HEX$(RetVal)
          END SELECT
        END IF 
        '================================
                     
    ' For applications using an API version earlier than 2.0, if the provider does not 
    ' return an icon (whether because the given device class is invalid or the provider 
    ' does not support icons), TAPI substitutes a generic Telephony line device icon. 
    ' For applications using API version 2.0 or later, TAPI substitutes the default line 
    ' icon only if the lpszDeviceClass parameter is "tapi/line", "" or NULL. For any other 
    ' device class, if the given device class is not valid or the provider does not support 
    ' icons for the class, lineGetIcon returns LINEERR_INVALDEVICECLASS.
    
    END FUNCTION   
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤'
    CALLBACK FUNCTION TapiCallback() AS LONG 
                    
    ' Operational Flow:
    ' * the first thing you must do with TAPI is line initialization 
    ' * Version negotiation is used to reach agreement between TAPI, service provider & this application.
    ' * Get information about each Device with lineGetDevCaps
    ' * open a device line with lineOpen
    ' * lineTranslateAddress is used to transtalate the phone number to canonical form
    ' * lineMakeCall is doing the actual job for you, communicating to your application via provided callback function
    ' * Finally, lineDrop, lineDeallocateCall, and lineClose will be called to make all required cleanup
    
      STATIC AppAPIver AS DWORD ' some TAPI calls need this instead of negotiated API version
      STATIC TotDev AS DWORD ' Total number of TAPI devices 
      STATIC DevSelected AS DWORD ' Current TAPI device
                
      LOCAL  ps AS paintstruct 
      STATIC rc AS RECT
      STATIC hIcon AS LONG
              
      LOCAL FieldFlag, hDC, RetVal AS LONG ' for TAPI icon
      LOCAL d AS DWORD
      LOCAL sTemp, sNumToDial AS STRING  
                  
        SELECT CASE CBMSG
            CASE %WM_INITDIALOG 
              CONTROL DISABLE hDlg, 301 ' Dialing Options  
              CONTROL DISABLE hDlg, 303 ' Line Config  
              CONTROL DISABLE hDlg, 305 ' Disable Dial 
              CONTROL DISABLE hDlg, 307 ' Disable Hang Up 
              DIM TapiLine( 0 ) ' Keep the Compiler happy  
              msgbox "create connection"
              sTemp = CreateConnection( "MyApp", TotDev ) ' MSGBOX STR$(TotDev),,"TotDev" 
              IF LEN(sTemp) THEN 
                ShowText "Error in CreateConnection()"
                DIALOG END CBHNDL
                EXIT FUNCTION
              END IF    
                   
              AppAPIver = %LoAPI ' Starting Version   
              sTemp = NegotiateAPIversions( TotDev, AppAPIver ) ' MSGBOX STR$(TotDev),,"TotDev" 
              IF LEN(sTemp) THEN 
                ShowText "NegotiateAPIversions()"
                DIALOG END CBHNDL
                EXIT FUNCTION
              END IF   
                             
              sTemp = GetLineDevCaps( TotDev ) 
              IF LEN(sTemp) THEN 
                ShowText "Error in GetLineDevCaps()"
                DIALOG END CBHNDL
                EXIT FUNCTION
              END IF 
       
              DevSelected = 0 ' TotDev ' Show the last Device
              COMBOBOX SELECT CBHNDL, 98, DevSelected+1 ' Set MsgBox to first Item   
              ShowText TRIM$(TapiLine(DevSelected).zLineName)
              IF TapiLine(DevSelected).LineSupportsVoiceCalls THEN CONTROL ENABLE hDlg, 305 'if Device supports voice
              CONTROL ENABLE hDlg, 303 ' Line Config 
              CONTROL ENABLE hDlg, 305 ' Dial 
              CONTROL ENABLE hDlg, 301 ' Dialing Options 
                       
              DroppingCall   = -1  ' Anything except zero or a +ve number
              RequestingCall = -1 
                                               
              GetClientRect   CBHNDL, rc ' For redrawing the Icon  
              sTemp = PaintDevIcon( DevSelected, hIcon ) ' Get a handle to the Icon
              IF LEN(sTemp) THEN ShowText "PaintDevIcon() Error: " + sTemp  
              InvalidateRect  CBHNDL, rc, 1 ' Draw the Icon 
                           
            CASE %WM_PAINT      
                hDC = BeginPaint(CBHNDL, ps)
                RetVal = DrawIconEx(hDc, 260, 8, hIcon, 32, 32, 0, 0, %DI_NORMAL) ' Draw the TAPI Icon  
                ReleaseDC CBHNDL, hDC 
                EndPaint  CBHNDL, ps  
                             
            CASE %WM_COMMAND
                SELECT CASE CBCTL 
                    CASE 301 ' Dial Properties  
                      TapiLine(DevSelected).zNumToDial = "555-1212"
                      sTemp = DialingPropertiesDialog( DevSelected, hDlg, AppAPIver )
                      IF LEN(sTemp) THEN ShowText "Error in DialingPropertiesDialog()" : sTemp = ""
                               
                    CASE 303 ' Line Config                       
                      sTemp = DeviceConfigDialog( DevSelected, hDlg ) ' DWORD
                      IF LEN(sTemp) THEN ShowText "Error in DeviceConfigDialog()" : sTemp = ""
                             
                    CASE 305 ' Dial   
                      CONTROL DISABLE hDlg, 305 ' Disable Dial   
                      sTemp = OpenLine( DevSelected ) ' Returns hLine
                      IF LEN(sTemp) THEN ShowText "OpenLine() Error: " + sTemp : EXIT FUNCTION
                                                  
                      CONTROL GET TEXT hDlg, 403 TO sTemp  ' get the user supplied phone number
                      TapiLine(DevSelected).zNumToDial = sTemp   
    '                  sTemp = ProcessCanonical( hLineApp, DevSelected )             
    '                  IF LEN(sTemp) THEN ShowText "ProcessCanonical() Error: " + sTemp : EXIT FUNCTION 
                      CONTROL ENABLE hDlg, 307 ' Enable Hang Up 
                      sTemp = MakeCallAsynch( TapiLine(DevSelected).zNumToDial ) ' zDialableString/zNumToDial 
                      IF LEN(sTemp) THEN ShowText "MakeCallAsynch() Error: " + sTemp : EXIT FUNCTION
    '****start of caller ID addition
                    case 777'listen to phone line
                    			local mylpCallStatus as LINECALLSTATUS
                    			local lret 					 as long
                    			local myLINECALLLIST as LINECALLLIST
                    			local theaddress     as dword
    											local cnt						 as long
    											local mydwLineStates as dword
    											local mydwAddressStates as dword
    											cnt=0                
                    			stemp = openline( devselected ) ' returns hline
                    			IF LEN(sTemp) THEN ShowText "OpenLine() Error: " + sTemp : EXIT FUNCTION                
                    			mydwLineStates = %LINEDEVSTATE_OTHER OR %LINEDEVSTATE_RINGING OR %LINEDEVSTATE_CONNECTED OR %LINEDEVSTATE_DISCONNECTED OR _
                    													%LINEDEVSTATE_MSGWAITON OR %LINEDEVSTATE_MSGWAITOFF OR %LINEDEVSTATE_INSERVICE OR %LINEDEVSTATE_OUTOFSERVICE OR _
                    													%LINEDEVSTATE_MAINTENANCE OR %LINEDEVSTATE_OPEN OR %LINEDEVSTATE_CLOSE OR %LINEDEVSTATE_NUMCALLS OR _
                    													%LINEDEVSTATE_NUMCOMPLETIONS OR %LINEDEVSTATE_TERMINALS OR %LINEDEVSTATE_ROAMMODE OR %LINEDEVSTATE_BATTERY OR _
                    													%LINEDEVSTATE_SIGNAL OR %LINEDEVSTATE_DEVSPECIFIC OR %LINEDEVSTATE_REINIT OR %LINEDEVSTATE_LOCK OR _
                    													%LINEDEVSTATE_CAPSCHANGE OR %LINEDEVSTATE_CONFIGCHANGE OR %LINEDEVSTATE_TRANSLATECHANGE OR _
                    													%LINEDEVSTATE_COMPLCANCEL OR %LINEDEVSTATE_REMOVED
                    			mydwAddressStates	= %LINEADDRESSSTATE_OTHER OR %LINEADDRESSSTATE_DEVSPECIFIC OR %LINEADDRESSSTATE_INUSEZERO OR %LINEADDRESSSTATE_INUSEONE OR _
                    													%LINEADDRESSSTATE_INUSEMANY OR %LINEADDRESSSTATE_NUMCALLS OR %LINEADDRESSSTATE_FORWARD OR _
                    													%LINEADDRESSSTATE_TERMINALS OR %LINEADDRESSSTATE_CAPSCHANGE								
                      		lineSetStatusMessages(hline,mydwLineStates ,mydwAddressStates)
    '                	while 0
    '                			INCR CNT
    '                			if CNT = 300 then exit function
    '                			sleep 1
    '                			lret = lineGetAddressID(hline, 	theaddress, ,,sizeof())
    '											myLINECALLLIST.dwTotalSize = len(LINECALLLIST)
    '											lret = lineGetNewCalls(hline, theaddress ,%LINECALLSELECT_ADDRESS ,myLINECALLLIST)
    '                			lret = lineGetLineDevStatus(hcall, mylpCallStatus	)
    '                			if mylpCallStatus.dwCallState = %LINECALLSTATE_OFFERING then
    '                				msgbox "offering"                 
    '                				exit function
    '                			end if
    '                	WEND          
    '****** End of Caller ID addition
                    CASE 307 ' Hang Up 
                      IF hCall <> 0 THEN
                        sTemp = DropCallAsynch( )
                        IF LEN(sTemp) THEN ShowText "DropCallAsynch() Error: " + sTemp 
                      END IF
                                
                    CASE 98 ' select a device
                        IF LOWRD(CBCTLMSG) = %CBN_SELENDOK THEN 
                          COMBOBOX GET TEXT hDlg, 98 TO sTemp
                          DevSelected = VAL(sTemp)   
                          CONTROL DISABLE hDlg, 305 ' Disable Dial if Device does not support voice
                          IF TapiLine(DevSelected).LineSupportsVoiceCalls THEN CONTROL ENABLE hDlg, 305
                          ShowText TRIM$(TapiLine(DevSelected).zLineName)
                          sTemp = PaintDevIcon( DevSelected, hIcon ) ' Get a handle to the Icon
                          IF LEN(sTemp) THEN ShowText "PaintDevIcon() Error: " + sTemp  
                          InvalidateRect CBHNDL, rc, 1 ' Draw the Icon   
                          sTemp = DeviceInfo( DevSelected )
                          MSGBOX sTemp,64,"TAPI info for Device " + STR$(DevSelected)
                        END IF 
                END SELECT   
                      
                 
            CASE %WM_SYSCOMMAND ' User closes window with X
                IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN  ' CLOSE hDbg ' hDbgf 
                    IF hLine THEN 
                      sTemp = ShutdownLine( )
                      IF LEN(sTemp) THEN MSGBOX sTemp,64, "ShutdownLine() Error" 
                    END IF
                    SendMessage CBHNDL,    %WM_CLOSE, 0, 0 ' Close main window
                END IF
        END SELECT
    END FUNCTION
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION PBMAIN 
              
        'OPEN "TAPIDbg.txt" FOR OUTPUT AS hDbg     ' for debuggin  PRINT #hDbg, "File Open"
            
        DIALOG NEW 0, "TAPI Test",  100, 10, 398, 268, %WS_SYSMENU  TO hDlg  
                                       
        CONTROL ADD COMBOBOX, hDlg, 98,                         ,  218,   008,   160,   260, %CBS_DROPDOWNLIST
                                                                      
        CONTROL ADD BUTTON,  hDlg, 305,                    "Dial", 008,   008,   050,    12 
        CONTROL ADD BUTTON,  hDlg, 307,                  "HangUp", 008,   022,   050,    12  
        CONTROL ADD BUTTON,  hDlg, 777,                  "listen", 008,   045,   050,    12      
        CONTROL ADD BUTTON,  hDlg, 301,                 "Options", 008,   068,   050,    12	
        CONTROL ADD BUTTON,  hDlg, 303,                 "LineCfg", 008,   088,   050,    12
                      
        CONTROL ADD TEXTBOX, hDlg, 403,             "13105551212", 068,   008,   60,    12
        CONTROL ADD TEXTBOX, hDlg, 401,                        "", 068,   032,   310,    200, _  
        %WS_VISIBLE OR %ES_MULTILINE OR %ES_WANTRETURN OR %ES_LEFT OR %ES_AUTOVSCROLL OR %WS_VSCROLL OR %WS_TABSTOP, %WS_EX_CLIENTEDGE 
        DIALOG SHOW MODAL hDlg CALL TapiCallback            
        'CLOSE hDbg ' hDbgf  
    END FUNCTION
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    I changed the privileges to be %LINECALLPRIVILEGE_MONITOR instead of %LINECALLPRIVILEGE_NONE. I click on the "listen" button and it opens the line. When a call comes in, the LINECALLBACKFUNC is never executed. Am I missing some step? I have tried numerous things and nothing has worked. I don't know what else to try at this point.

    To make sure that the phone is connect, the modem is giving caller ID info, etc, etc. I tried a nice shareware app called PHONETRAY FREE. This program will alert when an incoming call comes in and work fine. The *strange* thing is that when Phonetray is running, the callback function in my program is executed and work perfectly. Somehow this other app must initialize or unlock something somewhere. Does anybody have any clue what to check for?

    Thanks for your effort.
    Bill Scharf
  • Mike Doty
    Member
    • Feb 2005
    • 9263

    #2
    This might be a problem.
    Eighth Amendment:
    “Excessive bail shall not be required, nor excessive fines imposed, nor cruel and unusual punishments inflicted.”​

    Comment

    • Bill Scharf
      Member
      • Aug 2003
      • 123

      #3
      Mike,

      Thank you for the post. How could it be the modem drive if:
      1. Other caller ID apps work
      2. My caller ID app works when PHONETRAY FREE is running
      Could you explain this? Thanks!
      Bill Scharf

      Comment

      • Mike Doty
        Member
        • Feb 2005
        • 9263

        #4
        It was just additional information. Sorry if it doesn't apply to you.
        I use ani-232 adaptors so can't help.
        Eighth Amendment:
        “Excessive bail shall not be required, nor excessive fines imposed, nor cruel and unusual punishments inflicted.”​

        Comment

        • Bill Scharf
          Member
          • Aug 2003
          • 123

          #5
          I appreciate the reply anyway. Thanks!
          Bill Scharf

          Comment

          • colin glenn
            Member
            • Nov 2004
            • 638

            #6
            This is probably a question from left field, but went through something along these lines using a QB45 program I wrote many years ago, so if the memory is rusty, I'm sorry. And this is concerning the adapting the program from pure DOS to a Win32 environment.

            But, to get the program and modem talking and get caller id from the modem, under windows, I had to register my program as a recipient for dial information, then when windows "interrupted" with the message that the line was ringing, I then could interrogate the modem for the caller id information.

            But now, years later and source code having been eaten by a crash, I could not tell you what I did to inform windows that I was a ring recipient, nor the message windows sent when a ring came in.

            EDIT: And there was a modem string I sent to the modem to enable caller id prior to going passive and waiting for a call.
            Furcadia, an interesting online MMORPG in which you can create and program your own content.

            Comment

            • Scott Slater
              Member
              • Aug 1999
              • 1169

              #7
              Yes its:

              AT+VCID=1 for most v.92 modems

              or

              AT#CID=1

              The first string is the most commonly accepted.
              Scott Slater
              Summit Computer Networks, Inc.
              www.summitcn.com

              Comment

              • Scott Slater
                Member
                • Aug 1999
                • 1169

                #8
                Once the modem has been init'd with one of these strings successfully it should return the result along with the first ring like...

                Code:
                RING
                
                NMBR   8005551212
                NAME   JOE SMITH
                TIME   1426
                
                RING
                ...
                The return is structured like above with the ID (NAME, NMBR, TIME) always 4 in LEN, and the data beginning at the 8th character, on the same line.
                Last edited by Scott Slater; 21 Mar 2009, 07:42 AM. Reason: removed the : from the TIME return since it shouldn't be there
                Scott Slater
                Summit Computer Networks, Inc.
                www.summitcn.com

                Comment

                • Cliff Nichols
                  Member
                  • Aug 2006
                  • 3753

                  #9
                  You guys make me want to find equipment to test. (To my knowledge, Modem = ComPort = Serial Port = Who cares??? its still a Serial Port, whatever is attached is just a matter of protocol if it works or not???"


                  Its typically the same theory with any port/protocol (USB, Serial, Parallel, FireWire, anything external to the computer)

                  Can you show code? or examples? or a list of what you are using to test with???? (curiosity has gotten the best of me)
                  Engineer's Motto: If it aint broke take it apart and fix it

                  "If at 1st you don't succeed... call it version 1.0"

                  "Half of Programming is coding"....."The other 90% is DEBUGGING"

                  "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                  Comment

                  • Bill Scharf
                    Member
                    • Aug 2003
                    • 123

                    #10
                    Thank you all.

                    I cannot figure out how to send AT+VCID=1 to the modem. I tried using the pb program in samples\comms\ but it will not run when I adjust it to com3 (where the modem is accoring to the windows control panel). Using com1, it runs, but has no affect. I then searched through all the TAPI functions and found none that appeared to do this. How can I send this string to the modem?

                    Thanks!
                    Bill Scharf

                    Comment

                    • Mel Bishop
                      Member
                      • May 1999
                      • 3603

                      #11
                      May not apply here but I seem to recall that COM1 and COM3 share IRQ's as do COM2 and 4. Have you tried changing the IRQ of your modem to, say, COM2 or 4? Maybe...
                      There are no atheists in a fox hole or the morning of a math test.
                      If my flag offends you, I'll help you pack.

                      Comment

                      • Bill Scharf
                        Member
                        • Aug 2003
                        • 123

                        #12
                        Mel,

                        Thank you for your reply. That does sounds somewhat familar. I tried to mess with the com settings, but no luck. I don't believe the issue is the com port. If the com port is wrong, how could the Phonetray app work? If the com port is wrong, then why does my test app work when Phonetray is running?

                        Thanks again!
                        Bill Scharf

                        Comment

                        • Arthur Gomide
                          Member
                          • Dec 2005
                          • 995

                          #13
                          > I cannot figure out how to send AT+VCID=1 to the modem.

                          1- Open Control Panel
                          2- Phone & Modem Options
                          3- Select Modem tab
                          4- Select desired modem
                          5- Select Properties
                          6- Select Advanced tab
                          7- Type AT+VCID=1
                          8- Press OK

                          Maybe you need to reboot
                          "The trouble with quotes on the Internet is that you can never know if they are genuine." - Abraham Lincoln.

                          Comment

                          • Scott Slater
                            Member
                            • Aug 1999
                            • 1169

                            #14
                            You should be able to send AT followed by a $CR and see the result OK returned from the modem. Use Comm Send to send these strings right after the port is opened in your ap.
                            Scott Slater
                            Summit Computer Networks, Inc.
                            www.summitcn.com

                            Comment

                            • Arthur Gomide
                              Member
                              • Dec 2005
                              • 995

                              #15
                              Maybe this help
                              "The trouble with quotes on the Internet is that you can never know if they are genuine." - Abraham Lincoln.

                              Comment

                              • Dave Biggs
                                Member
                                • Feb 2001
                                • 3808

                                #16
                                Originally posted by Bill Scharf View Post
                                Mel,

                                .. I don't believe the issue is the com port. If the com port is wrong, how could the Phonetray app work? ..
                                Only one app at a time can have the comm port open.
                                If all else is closed down you should be able to talk to the modem (send AT commands etc) using HyperTerminal.

                                If something else has that port open already, it won't be available in HyperTerm's drop down list when you try to open a new connection...
                                Rgds, Dave

                                Comment

                                • Cliff Nichols
                                  Member
                                  • Aug 2006
                                  • 3753

                                  #17
                                  Dave hit this nail on the head with
                                  Only one app at a time can have the comm port open.
                                  That is one coffin often overlooked when developing (and I see it ALLLLL too often when getting calls that my software works, but using VB or (my ANTI-CHRIST "shudder" Labview) it does not work.

                                  the answer in most cases is to shut down the test code (including the environment it is running under) so that the port is forced closed (and in a few cases even then the only "Force" is a reboot

                                  Basically to the system its "He who has it 1st gets it"....and takes their ball and goes home if they do not share



                                  There are ways of making the software talk....(but even I have not collaborated all the mixtures yet when it comes to serial ports) but it can be done (or my intuition shows me it can)

                                  when it doubt of "What the FUBAR???" shut down everything possibly even considers the port, and if still not working then reboot and only run your test...if still failing then the hole has to be dug deeper
                                  Engineer's Motto: If it aint broke take it apart and fix it

                                  "If at 1st you don't succeed... call it version 1.0"

                                  "Half of Programming is coding"....."The other 90% is DEBUGGING"

                                  "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                                  Comment

                                  • Bill Scharf
                                    Member
                                    • Aug 2003
                                    • 123

                                    #18
                                    Thank you all for your help. I am still baffled by the original program's behavior. Contrary to what has been said above, that program *will* work with another peice of software (PhoneTray). It *will not* work by itself. I keep thinking that I am hallucinating, but I have duplicated this many times.

                                    The VB program at www.yes-tele.com does not seem to work correctly on the XP machines I tried it on. Maybe it is out-dated or specifically for a country outside the US? Either way, it gives immediate errors on all com ports.

                                    The only success I have had is avoiding TAPI all together and manually opening the com port:
                                    Code:
                                    local ncBytesInBuffer as long  
                                    local sBuffer         as string   
                                    local ncomm           as long           
                                    
                                    COMM OPEN "COM3" AS nComm
                                    sbuffer = "AT" + $CR
                                    COMM SEND nComm, sBuffer  
                                    ncBytesInBuffer = COMM(nComm, RXQUE)
                                    COMM RECV nComm, ncBytesInBuffer, sBuffer  
                                    msgbox sbuffer,,"results from AT"                  
                                    'this returns OK"
                                    sbuffer = "ATZ" + $CR
                                    COMM SEND nComm, sBuffer  
                                    ncBytesInBuffer = COMM(nComm, RXQUE)
                                    COMM RECV nComm, ncBytesInBuffer, sBuffer  
                                    msgbox sbuffer,,"results from ATZ"  
                                    'this returns OK"
                                    sbuffer = "AT+VCID=1" + $CR            
                                    
                                    COMM SEND nComm, sBuffer  
                                    ncBytesInBuffer = COMM(nComm, RXQUE)
                                    COMM RECV nComm, ncBytesInBuffer, sBuffer  
                                    msgbox sbuffer,,"results from ATZ"   
                                    'this returns OK"
                                    'this loop will find the data:
                                    DO 
                                    		COMM LINE INPUT NCOMM, SbUFFER
                                    		if LEN(sBuffer) then
                                    			msgbox sbuffer,,"testing"			
                                    		end if
                                    LOOP UNTIL instr(sBuffer, "NAME")
                                    comm close ncomm    
                                    'sbuffer will get the name data
                                    For that to work, I need a way to auto-detect which port has a modem and preferably where there is a dial-tone. Our users would like as much auto-detection as possible. I will keep researching this. Thank you all!
                                    Bill Scharf

                                    Comment

                                    • Peter Lameijn
                                      Member
                                      • Jun 2003
                                      • 3082

                                      #19
                                      Very helpful when developing TAPI applications:
                                      ftp://ftp.microsoft.com/developr/TAPI/tb20.zip (TAPI test application)
                                      ftp://ftp.microsoft.com/developr/TAPI/esp32.zip (Virtual TAPI provider)
                                      Last edited by Peter Lameijn; 27 Mar 2009, 05:23 PM.
                                      Regards,
                                      Peter

                                      "Simplicity is a prerequisite for reliability"

                                      Comment

                                      • Cliff Nichols
                                        Member
                                        • Aug 2006
                                        • 3753

                                        #20
                                        To my knowledge (correct me if I am wrong in explaining)
                                        1.) A Serial Port (ComPort) is its own device
                                        2.) No matter what is attached (internally such as a modem) or externally (such as a Motor Controller), it is considered an "Attached" device
                                        3.) (Lets skip 3 just to confuse or amuse)

                                        Much like any other protocol I have seen the following must hold true
                                        1.) Adhere to the protocol (or bridge of protocols) between port and device
                                        2.) The most stringent of both protocols is the one you need to assure if you can communicate.

                                        For example:
                                        (Depending on the OS) then a serial Port parameters are
                                        Baud: 1200
                                        guessing at the rest but best example
                                        Data bits: 8
                                        Parity: None
                                        Stop bits: 1

                                        and typically the attached device has its own parameters (unless set to custom for that device)
                                        lets say the typical 9600,8,N,1

                                        Now given the concept that you can make your "Best Guesstimation" at "Hey the port opened, and the device responded correctly" to find the correct combination....it is still a guesstimation (mostly right in 90% of the guesses, but there is always a fluke pitch"

                                        At your stage of the game, I will bet $$$ to doughnuts that most of your problems are they typical top mis-leads of any device attached.

                                        1.) Software SUCKS (was and after-thought of how to interface what may be a good piece of hardware

                                        2.) Examples Suck even more cause they "Just work" (but they only "Just Work" because only tested on 1 machine and in 1 circumstance
                                        (aka "Works on my Machine"...."ummm nope, I do not have a UPS attached"...ummm nope...why would I check if COM1 was already in USE??? etccccc.....)

                                        All in all you are on the right track, but the solution is in the details of what the attached device expects (usually the typical settings, but if not documented you are in trouble)

                                        Good news..you ruled out any hardware problems (because it works "Sometimes") tracking down why it does not work "Other times" is the problem
                                        Engineer's Motto: If it aint broke take it apart and fix it

                                        "If at 1st you don't succeed... call it version 1.0"

                                        "Half of Programming is coding"....."The other 90% is DEBUGGING"

                                        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                                        Comment

                                        Working...
                                        X