home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 10 / ioProg_10.iso / soft / platsdk / inetwork.exe / TAPI-S.cab / 65INCOMING.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-10  |  26.7 KB  |  1,084 lines

  1. #define UNICODE
  2. #include <list>
  3. #include <windows.h>
  4. #include <tapi3.h>
  5. #include "callnot.h"
  6. #include "resource.h"
  7.  
  8. //////////////////////////////////////////////////////////
  9. // T3IN.EXE
  10. //
  11. // Sample application that handling incoming TAPI calls.
  12. // In order to receive incoming calls, the application must
  13. // implement and register the outgoing ITCallNotification
  14. // interface.
  15. //
  16. // This application will register to recieve calls on
  17. // all addresses that support at least audioin and audioout.
  18. //
  19. // NOTE:  This application is limited to working with one call at
  20. // at time, and will not work correctly if multiple calls
  21. // are present at the same time.
  22. //////////////////////////////////////////////////////////
  23.  
  24. //////////////////////////////////////////////////////////
  25. // constants
  26. //////////////////////////////////////////////////////////
  27.  
  28. const DWORD MAXTERMINALS    = 5;
  29.  
  30. //////////////////////////////////////////////////////////
  31. // TYPEDEFS
  32. //////////////////////////////////////////////////////////
  33.  
  34. using namespace std;
  35. typedef list<CCallNotification *> CCallNotificationPtrList;
  36.  
  37.  
  38. //////////////////////////////////////////////////////////
  39. // GLOBALS
  40. //////////////////////////////////////////////////////////
  41.  
  42. HINSTANCE               ghInst;
  43. ITTAPI *                gpTapi;
  44. ITBasicCallControl *    gpCall;
  45. HWND                    ghDlg = NULL;
  46.  
  47. BSTR                    gbstrAudioIn;
  48. BSTR                    gbstrAudioOut;
  49. BSTR                    gbstrVideoIn;
  50. BSTR                    gbstrVideoOut;
  51.  
  52. WCHAR gszTapi30[] = L"TAPI 3.0 Incoming Call Sample";
  53.  
  54. // list of outgoing interface objects we have registered
  55. CCallNotificationPtrList gpCallNotificationList;
  56.  
  57. //////////////////////////////////////////////////////////
  58. // PROTOTYPES
  59. //////////////////////////////////////////////////////////
  60. BOOL
  61. CALLBACK
  62. MainDialogProc(
  63.                HWND hDlg,
  64.                UINT uMsg,
  65.                WPARAM wParam,
  66.                LPARAM lParam
  67.               );
  68.  
  69. HRESULT
  70. GetMediaTerminal(
  71.                  ITAddress *,
  72.                  BSTR bstrMedia,
  73.                  ITMediaTerminal ** ppMediaTerminal
  74.                 );
  75. HRESULT
  76. ListenOnAddresses();
  77.  
  78. HRESULT
  79. ListenOnThisAddress(
  80.                     ITAddress * pAddress
  81.                    );
  82.  
  83. HRESULT
  84. AnswerTheCall();
  85.  
  86. HRESULT
  87. DisconnectTheCall();
  88.  
  89. void
  90. ReleaseTheCall();
  91.  
  92. void
  93. DoMessage(
  94.           LPWSTR pszMessage
  95.          );
  96.  
  97. void
  98. SetStatusMessage(
  99.                  LPWSTR pszMessage
  100.                 );
  101.  
  102. HRESULT
  103. InitializeTapi();
  104.  
  105. void
  106. ShutdownTapi();
  107.  
  108. void
  109. EnableButton(
  110.              int ID
  111.             );
  112. void
  113. DisableButton(
  114.               int ID
  115.              );
  116.  
  117. //////////////////////////////////////////////////////////
  118. //
  119. //              FUNCTIONS
  120. //
  121. //////////////////////////////////////////////////////////
  122.  
  123. //////////////////////////////////////////////////////////
  124. // WinMain
  125. //////////////////////////////////////////////////////////
  126. int
  127. WINAPI
  128. WinMain(
  129.         HINSTANCE hInst,
  130.         HINSTANCE hPrevInst,
  131.         LPSTR lpCmdLine,
  132.         int nCmdShow
  133.        )
  134. {
  135.     ghInst = hInst;
  136.  
  137.     
  138.     // need to coinit
  139.     if (!SUCCEEDED(CoInitialize(NULL)))
  140.     {
  141.         return 0;
  142.     }
  143.  
  144.     // do all tapi initialization
  145.     if (S_OK != InitializeTapi())
  146.     {
  147.         return 0;
  148.     }
  149.     
  150.     // everything is initialized, so
  151.     // start the main dialog box
  152.     DialogBox(
  153.               ghInst,
  154.               MAKEINTRESOURCE(IDD_MAINDLG),
  155.               NULL,
  156.               MainDialogProc
  157.              );
  158.  
  159.  
  160.     // clean up
  161.     ShutdownTapi();
  162.     
  163.     CoUninitialize();
  164.  
  165.     return 1;
  166. }
  167.  
  168.  
  169. //////////////////////////////////////////////////////////////
  170. // InitializeTapi
  171. //
  172. // Various initializations
  173. ///////////////////////////////////////////////////////////////
  174. HRESULT
  175. InitializeTapi()
  176. {
  177.     HRESULT         hr;
  178.     LPWSTR          psz;
  179.  
  180.     
  181.     // cocreate the TAPI object
  182.     hr = CoCreateInstance(
  183.                           CLSID_TAPI,
  184.                           NULL,
  185.                           CLSCTX_INPROC_SERVER,
  186.                           IID_ITTAPI,
  187.                           (LPVOID *)&gpTapi
  188.                          );
  189.  
  190.     if (hr != S_OK)
  191.     {
  192.         DoMessage(L"CoCreateInstance on TAPI failed");
  193.         return hr;
  194.     }
  195.  
  196.     // call initialize.  this must be called before
  197.     // any other tapi functions are called.
  198.     hr = gpTapi->Initialize();
  199.  
  200.     if (S_OK != hr)
  201.     {
  202.         DoMessage(L"TAPI failed to initialize");
  203.  
  204.         gpTapi->Release();
  205.         gpTapi = NULL;
  206.         
  207.         return hr;
  208.     }
  209.  
  210.  
  211.     // convert the TAPIMEDIATYPEs to BSTRs for
  212.     // convenience throughout the program
  213.  
  214.     StringFromIID( TAPIMEDIATYPE_AudioIn, &psz );
  215.     gbstrAudioIn = SysAllocString( psz );
  216.     CoTaskMemFree( psz );
  217.  
  218.     StringFromIID( TAPIMEDIATYPE_AudioOut, &psz );
  219.     gbstrAudioOut = SysAllocString( psz );
  220.     CoTaskMemFree( psz );
  221.  
  222.     StringFromIID( TAPIMEDIATYPE_VideoIn, &psz );
  223.     gbstrVideoIn = SysAllocString( psz );
  224.     CoTaskMemFree( psz );
  225.  
  226.     StringFromIID( TAPIMEDIATYPE_VideoOut, &psz );
  227.     gbstrVideoOut = SysAllocString( psz );
  228.     CoTaskMemFree( psz );
  229.  
  230.     // find all address objects that
  231.     // we will use to listen for calls on
  232.     hr = ListenOnAddresses();
  233.  
  234.     if (S_OK != hr)
  235.     {
  236.         DoMessage(L"Could not find any addresses to listen on");
  237.  
  238.         gpTapi->Release();
  239.         gpTapi = NULL;
  240.  
  241.         return hr;
  242.     }
  243.  
  244.     return S_OK;
  245.  
  246. }
  247.  
  248.  
  249. ///////////////////////////////////////////////////////////////
  250. // ShutdownTapi
  251. ///////////////////////////////////////////////////////////////
  252. void
  253. ShutdownTapi()
  254. {
  255.     CCallNotificationPtrList::iterator i;
  256.     // if there is still a call,
  257.     // release it
  258.     if (NULL != gpCall)
  259.     {
  260.         gpCall->Release();
  261.         gpCall = NULL;
  262.     }
  263.  
  264.  
  265.     // Release all CallNotification objects
  266.     for (
  267.          i = gpCallNotificationList.begin();
  268.          i != gpCallNotificationList.end();
  269.          i++
  270.         )
  271.     {
  272.         
  273.         (*i)->Shutdown();
  274.         
  275.         // At this point, we should call Unadvise on
  276.         // the ConnectionPoint.  However, TAPI 3.0
  277.         // does not support Unadvise for the ITCallNotification
  278.         // interface.  So, here we just release the object
  279.         (*i)->Release();
  280.     }
  281.     
  282.     // release main object.
  283.     if (NULL != gpTapi)
  284.     {
  285.         gpTapi->Shutdown();
  286.         gpTapi->Release();
  287.     }
  288.  
  289.     // free the BSTRs
  290.     SysFreeString( gbstrAudioIn );
  291.     SysFreeString( gbstrAudioOut );
  292.     SysFreeString( gbstrVideoIn );
  293.     SysFreeString( gbstrVideoOut );
  294. }
  295.  
  296.  
  297. ///////////////////////////////////////////////////////////////////////////
  298. // MainDlgProc
  299. ///////////////////////////////////////////////////////////////////////////
  300. BOOL
  301. CALLBACK
  302. MainDialogProc(
  303.                HWND hDlg,
  304.                UINT uMsg,
  305.                WPARAM wParam,
  306.                LPARAM lParam
  307.               )
  308. {
  309.     switch (uMsg)
  310.     {
  311.         case WM_INITDIALOG:
  312.         {
  313.             // set up dialog
  314.             ghDlg = hDlg;
  315.             
  316.             DisableButton( IDC_ANSWER );
  317.             DisableButton( IDC_DISCONNECT );
  318.  
  319.             SetStatusMessage( L"Waiting for a call..." );
  320.  
  321.             return 0;
  322.         }
  323.  
  324.         case WM_COMMAND:
  325.         {
  326.             if ( LOWORD(wParam) == IDCANCEL )
  327.             {
  328.                 // quit
  329.                 EndDialog( hDlg, 0 );
  330.  
  331.                 return 1;
  332.             }
  333.  
  334.             switch ( LOWORD(wParam) )
  335.             {
  336.                 // dial request
  337.                 case IDC_ANSWER:
  338.                 {
  339.                     SetStatusMessage(L"Answering...");
  340.                     // answer the call
  341.                     if ( S_OK == AnswerTheCall() )
  342.                     {
  343.                         SetStatusMessage(L"Connected");
  344.  
  345.                         EnableButton( IDC_DISCONNECT );
  346.                         DisableButton( IDC_ANSWER );
  347.                     }
  348.                     else
  349.                     {
  350.                         DisableButton( IDC_ANSWER );
  351.                         DoMessage(L"Answer failed");
  352.                         SetStatusMessage(L"Waiting for a call...");
  353.                     }
  354.  
  355.                     return 1;
  356.                 }
  357.  
  358.                 // disconnect request
  359.                 case IDC_DISCONNECT:
  360.                 {
  361.                     SetStatusMessage(L"Disconnecting...");
  362.                     // disconnect
  363.                     if (S_OK != DisconnectTheCall())
  364.                     {
  365.                         DoMessage(L"Disconnect failed");
  366.                     }
  367.  
  368.                     return 1;
  369.                 }
  370.  
  371.                 // disconnected notification
  372.                 case IDC_DISCONNECTED:
  373.                 {
  374.                     // release
  375.                     ReleaseTheCall();
  376.  
  377.                     EnableButton( IDOK );
  378.                     DisableButton( IDC_DISCONNECT );
  379.  
  380.                     SetStatusMessage(L"Waiting for a call...");
  381.                     
  382.                     return 1;
  383.                 }
  384.                 default:
  385.  
  386.                     return 0;
  387.             }
  388.         }
  389.         default:
  390.  
  391.             return 0;
  392.     }
  393. }
  394.  
  395.  
  396. ////////////////////////////////////////////////////////////////////////
  397. // ListenOnAddresses
  398. //
  399. // This procedure will find all addresses that support audioin and audioout
  400. // and will call ListenOnThisAddress to start listening on it.
  401. ////////////////////////////////////////////////////////////////////////
  402. HRESULT
  403. ListenOnAddresses()
  404. {
  405.     HRESULT             hr = S_OK;
  406.     IEnumAddress *      pEnumAddress;
  407.     ITAddress *         pAddress;
  408.     ITMediaSupport *    pMediaSupport;
  409.     VARIANT_BOOL        bSupport;
  410.  
  411.     // enumerate the addresses
  412.     hr = gpTapi->_EnumerateAddresses( &pEnumAddress );
  413.  
  414.     if (S_OK != hr)
  415.     {
  416.         return hr;
  417.     }
  418.  
  419.     while ( TRUE )
  420.     {
  421.         // get the next address
  422.         hr = pEnumAddress->Next( 1, &pAddress, NULL );
  423.  
  424.         if (S_OK != hr)
  425.         {
  426.             break;
  427.         }
  428.  
  429.         pAddress->QueryInterface( IID_ITMediaSupport, (void **)&pMediaSupport );
  430.  
  431.         // does it support AudioIn?
  432.         pMediaSupport->QueryMediaType(
  433.                                       gbstrAudioIn,
  434.                                       &bSupport
  435.                                      );
  436.  
  437.         if (bSupport)
  438.         {
  439.             // does it also support AudioOut?
  440.             pMediaSupport->QueryMediaType(
  441.                                           gbstrAudioOut,
  442.                                           &bSupport
  443.                                          );
  444.  
  445.             if (bSupport)
  446.             {
  447.                 // listen
  448.                 hr = ListenOnThisAddress( pAddress );
  449.                 if (S_OK != hr)
  450.                 {
  451.                     DoMessage(L"Listen failed on an address");
  452.                 }
  453.             }
  454.         }
  455.  
  456.         pMediaSupport->Release();
  457.         pAddress->Release();
  458.     }
  459.  
  460.     pEnumAddress->Release();
  461.     
  462.     return S_OK;
  463. }
  464.  
  465.  
  466. ///////////////////////////////////////////////////////////////////
  467. // ListenOnThisAddress
  468. //
  469. // Perform the steps involved in setting up an address to listen
  470. // for calls.  Setting up an application to listen for calls is a two
  471. // step process.
  472. //
  473. // First, the app must call RegisterCallTypes
  474. // on the address that it wants calls on
  475. //
  476. // Second, it must register it's implementation of ITCallNotification
  477. // with the address.  Registration is done via COM's ConnectionPoint
  478. // methods.  See the COM documentation for more informations on
  479. // ConnectionPoints
  480. //    
  481. ///////////////////////////////////////////////////////////////////
  482. HRESULT
  483. ListenOnThisAddress(
  484.                     ITAddress * pAddress
  485.                    )
  486. {
  487.     HRESULT hr = S_OK;
  488.     IConnectionPointContainer * pCPC;
  489.     IConnectionPoint *          pCP;
  490.     CCallNotification *         pCallNotification;
  491.     DWORD                       dwCookie;
  492.     VARIANT var;
  493.  
  494.     // RegisterCallTypes takes an array (in a variant) of
  495.     // MediaTypes for the address to listen for.
  496.     // If NULL is specified for the array, that means to listen
  497.     // for all the media types that the address supports.
  498.     //
  499.     // Since we already know the address supports audioin/audioout,
  500.     // just tell it to listen for all types.  Also, we will tell
  501.     // it that we are only interested in being the owner of calls,
  502.     // not monitoring
  503.  
  504.     VariantInit( &var );
  505.     var.vt = VT_ARRAY;
  506.     var.parray = NULL;
  507.  
  508.     hr = pAddress->RegisterCallTypes(
  509.                                      FALSE,
  510.                                      TRUE,  // Want to be owner
  511.                                      FALSE, // Don't want to be monitor
  512.                                      var    // mediatypes
  513.                                     );
  514.  
  515.     if (S_OK != hr)
  516.     {
  517.         return hr;
  518.     }
  519.  
  520.     // now we need to register our outgoing interface through
  521.     // the ConnectionPoint methods.
  522.     
  523.     // First we create our CCallNotification object
  524.     pCallNotification = new CCallNotification;
  525.  
  526.     if (NULL == pCallNotification)
  527.     {
  528.         return E_OUTOFMEMORY;
  529.     }
  530.  
  531.     // initialize the object
  532.     hr = pCallNotification->Initialize( pAddress );
  533.  
  534.     if (S_OK != hr)
  535.     {
  536.         pCallNotification->Release();
  537.         return hr;
  538.     }
  539.     
  540.     // get the IConnectionPointContainer interface
  541.     // from the address object
  542.     hr = pAddress->QueryInterface( 
  543.                                   IID_IConnectionPointContainer, 
  544.                                   (void **)&pCPC 
  545.                                  );
  546.  
  547.     if (S_OK != hr)
  548.     {
  549.         pCallNotification->Release();
  550.         pCallNotification = NULL;
  551.         return hr;
  552.     }
  553.  
  554.     // find the ConnectionPoint we are interested in
  555.     hr = pCPC->FindConnectionPoint( IID_ITCallNotification, &pCP );
  556.  
  557.     pCPC->Release();
  558.  
  559.     if (S_OK != hr)
  560.     {
  561.         pCallNotification->Release();
  562.         pCallNotification = NULL;
  563.         return hr;
  564.     }
  565.  
  566.     // call the advise function
  567.     //
  568.     // if this function succeeds, the address will start
  569.     // listening for calls.
  570.     hr = pCP->Advise(
  571.                      (IUnknown *)pCallNotification,
  572.                      &dwCookie
  573.                     );
  574.  
  575.     pCP->Release();
  576.     
  577.     if (S_OK != hr)
  578.     {
  579.         pCallNotification->Release();
  580.         pCallNotification = NULL;
  581.         return hr;
  582.     }
  583.  
  584.     // save the notification object
  585.     // note that normally you would want
  586.     // to save the dwCookie as well.  Refer
  587.     // to the COM ConnectionPoint documentation
  588.     // for more details.
  589.     gpCallNotificationList.push_back( pCallNotification );
  590.     
  591.     return S_OK;
  592. }
  593.                     
  594. /////////////////////////////////////////////////////////
  595. // GetMediaTerminal
  596. //
  597. // Creates a MediaTerminal for the bstrMediaType passed
  598. // in, using the default terminal for the bstrMediaType
  599. //
  600. /////////////////////////////////////////////////////////
  601. HRESULT
  602. GetMediaTerminal(
  603.                  ITAddress * pAddress,
  604.                  BSTR bstrMediaType,
  605.                  ITMediaTerminal ** ppMediaTerminal
  606.                 )
  607. {
  608.     HRESULT             hr = S_OK;
  609.     ITTerminalSupport * pTerminalSupport;
  610.     ITTerminal *        pTerminal;
  611.  
  612.     // get the terminal support interface
  613.     pAddress->QueryInterface( IID_ITTerminalSupport, (void **)&pTerminalSupport );
  614.     
  615.     // get the default terminal for MediaType
  616.     hr = pTerminalSupport->GetDefaultTerminal(
  617.                                               bstrMediaType,
  618.                                               &pTerminal
  619.                                              );
  620.  
  621.  
  622.     pTerminalSupport->Release();
  623.  
  624.     if (S_OK != hr)
  625.     {
  626.         return hr;
  627.     }
  628.  
  629.     // Create a media terminal for MediaType
  630.     // Use the default terminal we just got
  631.     hr = gpTapi->CreateMediaTerminal(
  632.                                      bstrMediaType,
  633.                                      pTerminal,
  634.                                      ppMediaTerminal
  635.                                     );
  636.  
  637.     pTerminal->Release();
  638.  
  639.     if (S_OK != hr)
  640.     {
  641.         return hr;
  642.     }
  643.  
  644.     return S_OK;
  645.  
  646. }
  647.  
  648. /////////////////////////////////////////////////////////
  649. // GetVideoInMediaTerminal
  650. //
  651. // Creates a MediaTerminal for the VideoIn mediatype 
  652. // This is a dynamic terminal type.
  653. //
  654. /////////////////////////////////////////////////////////
  655. HRESULT
  656. GetVideoInMediaTerminal(
  657.                  ITAddress * pAddress,
  658.                  ITMediaTerminal ** ppMediaTerminal
  659.                 )
  660. {
  661.     HRESULT             hr = S_OK;
  662.     ITTerminalSupport * pTerminalSupport;
  663.     ITTerminal *        pTerminal;
  664.  
  665.     // get the terminal support interface
  666.     pAddress->QueryInterface( IID_ITTerminalSupport, (void **)&pTerminalSupport );
  667.     
  668.     BSTR bstrTerminalClass;
  669.     LPOLESTR lpTerminalClass;
  670.  
  671.     StringFromIID(
  672.                 CLSID_VideoWindowTerm,
  673.                 &lpTerminalClass
  674.                 );
  675.  
  676.     bstrTerminalClass = SysAllocString ( lpTerminalClass );
  677.  
  678.     CoTaskMemFree( lpTerminalClass );
  679.  
  680.     hr = pTerminalSupport->CreateTerminal(
  681.         bstrTerminalClass,
  682.         &pTerminal
  683.         );
  684.  
  685.     SysFreeString( bstrTerminalClass );
  686.     pTerminalSupport->Release();
  687.  
  688.     if (FAILED(hr))
  689.     {
  690.         return hr;
  691.     }
  692.  
  693.     // Create a media terminal for MediaType
  694.     // Use the default terminal we just got
  695.     hr = gpTapi->CreateMediaTerminal(
  696.                                      gbstrVideoIn,
  697.                                      pTerminal,
  698.                                      ppMediaTerminal
  699.                                     );
  700.  
  701.     pTerminal->Release();
  702.  
  703.     if (S_OK != hr)
  704.     {
  705.         return hr;
  706.     }
  707.  
  708.     return S_OK;
  709.  
  710. }
  711.  
  712. /////////////////////////////////////////////////////////////////
  713. // CreateMediaTerminals
  714. //
  715. // Create audioin and audioout terminals. Videoin and videoout terminals
  716. // are created only when the address supports them.
  717. //
  718. // This function assumes that ppMediaTerminals has a size no less than four.
  719. /////////////////////////////////////////////////////////////////
  720. HRESULT
  721. CreateMediaTerminals(
  722.                      ITAddress *pAddress,
  723.                      ITMediaTerminal ** ppMediaTerminals,
  724.                      PLONG pNumMediaTerminals
  725.                     )
  726. {
  727.     int count = 0;
  728.     HRESULT hr;
  729.  
  730.     // get the mediaterminal for audioin
  731.     hr = GetMediaTerminal(
  732.                           pAddress,
  733.                           gbstrAudioIn,
  734.                           &ppMediaTerminals[count]
  735.                          );
  736.  
  737.     if (S_OK != hr)
  738.     {
  739.         return hr;
  740.     }
  741.     
  742.     count ++;
  743.  
  744.     // get the mediaterminal for audioout
  745.     hr = GetMediaTerminal(
  746.                           pAddress,
  747.                           gbstrAudioOut,
  748.                           &ppMediaTerminals[count]
  749.                          );
  750.  
  751.     if (S_OK != hr)
  752.     {
  753.         ppMediaTerminals[0]->Release();
  754.         return hr;
  755.     }
  756.  
  757.     count ++;
  758.     
  759.     // Find out if the address supports video.
  760.     ITMediaSupport *pMediaSupport;
  761.     VARIANT_BOOL    bSupport;
  762.  
  763.     pAddress->QueryInterface( IID_ITMediaSupport, (void **)&pMediaSupport );
  764.  
  765.     // does it support VideoIn?
  766.     pMediaSupport->QueryMediaType(
  767.                                   gbstrVideoIn,
  768.                                   &bSupport
  769.                                  );
  770.  
  771.     if (bSupport)
  772.     {
  773.         // get the mediaterminal for VideoIn
  774.         hr = GetVideoInMediaTerminal(
  775.                                      pAddress,
  776.                                      &ppMediaTerminals[count]
  777.                                     );
  778.  
  779.         if (S_OK == hr)
  780.         {
  781.             count ++;
  782.         }
  783.  
  784.         // does it also support VideoOut?
  785.         pMediaSupport->QueryMediaType(
  786.             gbstrVideoOut,
  787.             &bSupport
  788.             );
  789.  
  790.         if (bSupport)
  791.         {
  792.             // get the mediaterminal for Videoout
  793.             hr = GetMediaTerminal(
  794.                                   pAddress,
  795.                                   gbstrVideoOut,
  796.                                   &ppMediaTerminals[count]
  797.                                  );
  798.     
  799.             if (S_OK == hr)
  800.             {
  801.                 count ++;
  802.             }
  803.         }
  804.     }
  805.  
  806.     pMediaSupport->Release();
  807.  
  808.     *pNumMediaTerminals = count;
  809.  
  810.     return S_OK;
  811. }
  812.  
  813. /////////////////////////////////////////////////////////////////
  814. // CreateMediaTerminalSafeArray
  815. //
  816. /////////////////////////////////////////////////////////////////
  817. SAFEARRAY *
  818. CreateMediaTerminalSafeArray(
  819.                              ITMediaTerminal ** ppMediaTerminals,
  820.                              LONG nNumMediaTerminals
  821.                             )
  822. {
  823.     SAFEARRAY *             psa;
  824.     SAFEARRAYBOUND          sabound[1];
  825.  
  826.     // create a safearray with two elements
  827.     // to pass the mediaterminals to tapi
  828.     sabound[0].lLbound = 0;
  829.     sabound[0].cElements = nNumMediaTerminals;
  830.  
  831.     psa = SafeArrayCreate(
  832.                           VT_UNKNOWN,
  833.                           1,
  834.                           sabound
  835.                          );
  836.  
  837.     if (NULL != psa)
  838.     {
  839.         // save them in the safearray
  840.         for (long i = 0; i < nNumMediaTerminals; i ++)
  841.         {
  842.             SafeArrayPutElement(
  843.                             psa,
  844.                             &i,
  845.                             ppMediaTerminals[i]
  846.                            );
  847.         }
  848.     }
  849.     return psa;
  850. }
  851.  
  852. /////////////////////////////////////////////////////////////////
  853. // ReleaseMediaTerminals
  854. //
  855. /////////////////////////////////////////////////////////////////
  856. void
  857. ReleaseMediaTerminals(
  858.                       ITMediaTerminal ** ppMediaTerminals,
  859.                       LONG nNumMediaTerminals
  860.                      )
  861. {
  862.     for (long i = 0; i < nNumMediaTerminals; i ++)
  863.     {
  864.         if (ppMediaTerminals[i])
  865.         {
  866.             ppMediaTerminals[i]->Release();
  867.         }
  868.     }
  869. }
  870.  
  871. /////////////////////////////////////////////////////////////////////
  872. // Answer the call
  873. /////////////////////////////////////////////////////////////////////
  874. HRESULT
  875. AnswerTheCall()
  876. {
  877.     HRESULT                 hr;
  878.     ITCallInfo *            pCallInfo;
  879.     ITAddress *             pAddress;
  880.     ITMediaTerminal *       ppMediaTerminals[MAXTERMINALS];
  881.     long                    nNumMediaTerminals = MAXTERMINALS;
  882.     SAFEARRAY *             psa;
  883.  
  884.  
  885.     
  886.     if (NULL == gpCall)
  887.     {
  888.         return E_UNEXPECTED;
  889.     }
  890.  
  891.  
  892.     // get the address object of this call
  893.     gpCall->QueryInterface( IID_ITCallInfo, (void**)&pCallInfo );
  894.     pCallInfo->get_Address( &pAddress );
  895.     pCallInfo->Release();
  896.  
  897.  
  898.     // create the media terminals for this call
  899.     hr = CreateMediaTerminals( 
  900.         pAddress, 
  901.         ppMediaTerminals, 
  902.         &nNumMediaTerminals
  903.         );
  904.  
  905.  
  906.     // release the address
  907.     pAddress->Release();
  908.  
  909.     
  910.     if (S_OK != hr)
  911.     {
  912.         gpCall->Release();
  913.         gpCall = NULL;
  914.         return hr;
  915.     }
  916.  
  917.     psa = CreateMediaTerminalSafeArray(ppMediaTerminals, nNumMediaTerminals);
  918.  
  919.     if (S_OK != hr)
  920.     {
  921.         gpCall->Release();
  922.         gpCall = NULL;
  923.         ReleaseMediaTerminals(ppMediaTerminals, nNumMediaTerminals);
  924.         return hr;
  925.     }
  926.  
  927.     // put the safearray in a variant
  928.     VARIANT                 var;
  929.     VariantInit(&var);
  930.     var.vt = VT_ARRAY;
  931.     var.parray = psa;
  932.  
  933.     // call SelectMediaTerminals
  934.     hr = gpCall->SelectMediaTerminals(
  935.                                       var
  936.                                      );
  937.  
  938.     ReleaseMediaTerminals(ppMediaTerminals, nNumMediaTerminals);
  939.  
  940.     SafeArrayDestroy( psa );
  941.  
  942.     if (S_OK != hr)
  943.     {
  944.         gpCall->Release();
  945.         gpCall = NULL;
  946.         return hr;
  947.     }
  948.     
  949.     // answer the call
  950.     hr = gpCall->Answer();
  951.  
  952.     return hr;
  953. }
  954.  
  955. //////////////////////////////////////////////////////////////////////
  956. // DisconnectTheCall
  957. //
  958. // Disconnects the call
  959. //////////////////////////////////////////////////////////////////////
  960. HRESULT
  961. DisconnectTheCall()
  962. {
  963.     HRESULT         hr = S_OK;
  964.  
  965.     if (NULL != gpCall)
  966.     {
  967.         hr = gpCall->Disconnect( DC_NORMAL );
  968.  
  969.         gpCall->Release();
  970.         gpCall = NULL;
  971.     
  972.         return hr;
  973.     }
  974.  
  975.     return S_FALSE;
  976. }
  977.  
  978. //////////////////////////////////////////////////////////////////////
  979. // ReleaseTheCall
  980. //
  981. // Releases the call
  982. //////////////////////////////////////////////////////////////////////
  983. void
  984. ReleaseTheCall()
  985. {
  986.     if (NULL != gpCall)
  987.     {
  988.         gpCall->Release();
  989.         gpCall = NULL;
  990.     }
  991. }
  992.  
  993.  
  994. ///////////////////////////////////////////////////////////////////
  995. //
  996. // HELPER FUNCTIONS
  997. //
  998. ///////////////////////////////////////////////////////////////////
  999.  
  1000.  
  1001. ///////////////////////////////////////////////////////////////////
  1002. // DoMessage
  1003. ///////////////////////////////////////////////////////////////////
  1004. void
  1005. DoMessage(
  1006.           LPWSTR pszMessage
  1007.          )
  1008. {
  1009.     MessageBox(
  1010.                ghDlg,
  1011.                pszMessage,
  1012.                gszTapi30,
  1013.                MB_OK
  1014.               );
  1015. }
  1016.  
  1017.  
  1018. //////////////////////////////////////////////////////////////////
  1019. // SetStatusMessage
  1020. //////////////////////////////////////////////////////////////////
  1021. void
  1022. SetStatusMessage(
  1023.                  LPWSTR pszMessage
  1024.                 )
  1025. {
  1026.     SetDlgItemText(
  1027.                    ghDlg,
  1028.                    IDC_STATUS,
  1029.                    pszMessage
  1030.                   );
  1031. }
  1032.  
  1033. ///////////////////////////////////////////////////////////////
  1034. // EnableButton
  1035. //
  1036. // Enable, make default, and setfocus to a button
  1037. ///////////////////////////////////////////////////////////////
  1038. void
  1039. EnableButton(
  1040.              int ID
  1041.             )
  1042. {
  1043.     SendDlgItemMessage(
  1044.                        ghDlg,
  1045.                        ID,
  1046.                        BM_SETSTYLE,
  1047.                        BS_DEFPUSHBUTTON,
  1048.                        0
  1049.                       );
  1050.     EnableWindow(
  1051.                  GetDlgItem( ghDlg, ID ),
  1052.                  TRUE
  1053.                 );
  1054.     SetFocus(
  1055.              GetDlgItem( ghDlg, ID )
  1056.             );
  1057. }
  1058.  
  1059. //////////////////////////////////////////////////////////////
  1060. // DisableButton
  1061. //
  1062. // Disable a button
  1063. //////////////////////////////////////////////////////////////
  1064. void
  1065. DisableButton(
  1066.               int ID
  1067.              )
  1068. {
  1069.     SendDlgItemMessage(
  1070.                        ghDlg,
  1071.                        ID,
  1072.                        BM_SETSTYLE,
  1073.                        BS_PUSHBUTTON,
  1074.                        0
  1075.                       );
  1076.     EnableWindow(
  1077.                  GetDlgItem( ghDlg, ID ),
  1078.                  FALSE
  1079.                 );
  1080. }
  1081.  
  1082.  
  1083.  
  1084.