home *** CD-ROM | disk | FTP | other *** search
- #define UNICODE
- #include <list>
- #include <windows.h>
- #include <tapi3.h>
- #include "callnot.h"
- #include "resource.h"
-
- //////////////////////////////////////////////////////////
- // T3IN.EXE
- //
- // Sample application that handling incoming TAPI calls.
- // In order to receive incoming calls, the application must
- // implement and register the outgoing ITCallNotification
- // interface.
- //
- // This application will register to recieve calls on
- // all addresses that support at least audioin and audioout.
- //
- // NOTE: This application is limited to working with one call at
- // at time, and will not work correctly if multiple calls
- // are present at the same time.
- //////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////
- // constants
- //////////////////////////////////////////////////////////
-
- const DWORD MAXTERMINALS = 5;
-
- //////////////////////////////////////////////////////////
- // TYPEDEFS
- //////////////////////////////////////////////////////////
-
- using namespace std;
- typedef list<CCallNotification *> CCallNotificationPtrList;
-
-
- //////////////////////////////////////////////////////////
- // GLOBALS
- //////////////////////////////////////////////////////////
-
- HINSTANCE ghInst;
- ITTAPI * gpTapi;
- ITBasicCallControl * gpCall;
- HWND ghDlg = NULL;
-
- BSTR gbstrAudioIn;
- BSTR gbstrAudioOut;
- BSTR gbstrVideoIn;
- BSTR gbstrVideoOut;
-
- WCHAR gszTapi30[] = L"TAPI 3.0 Incoming Call Sample";
-
- // list of outgoing interface objects we have registered
- CCallNotificationPtrList gpCallNotificationList;
-
- //////////////////////////////////////////////////////////
- // PROTOTYPES
- //////////////////////////////////////////////////////////
- BOOL
- CALLBACK
- MainDialogProc(
- HWND hDlg,
- UINT uMsg,
- WPARAM wParam,
- LPARAM lParam
- );
-
- HRESULT
- GetMediaTerminal(
- ITAddress *,
- BSTR bstrMedia,
- ITMediaTerminal ** ppMediaTerminal
- );
- HRESULT
- ListenOnAddresses();
-
- HRESULT
- ListenOnThisAddress(
- ITAddress * pAddress
- );
-
- HRESULT
- AnswerTheCall();
-
- HRESULT
- DisconnectTheCall();
-
- void
- ReleaseTheCall();
-
- void
- DoMessage(
- LPWSTR pszMessage
- );
-
- void
- SetStatusMessage(
- LPWSTR pszMessage
- );
-
- HRESULT
- InitializeTapi();
-
- void
- ShutdownTapi();
-
- void
- EnableButton(
- int ID
- );
- void
- DisableButton(
- int ID
- );
-
- //////////////////////////////////////////////////////////
- //
- // FUNCTIONS
- //
- //////////////////////////////////////////////////////////
-
- //////////////////////////////////////////////////////////
- // WinMain
- //////////////////////////////////////////////////////////
- int
- WINAPI
- WinMain(
- HINSTANCE hInst,
- HINSTANCE hPrevInst,
- LPSTR lpCmdLine,
- int nCmdShow
- )
- {
- ghInst = hInst;
-
-
- // need to coinit
- if (!SUCCEEDED(CoInitialize(NULL)))
- {
- return 0;
- }
-
- // do all tapi initialization
- if (S_OK != InitializeTapi())
- {
- return 0;
- }
-
- // everything is initialized, so
- // start the main dialog box
- DialogBox(
- ghInst,
- MAKEINTRESOURCE(IDD_MAINDLG),
- NULL,
- MainDialogProc
- );
-
-
- // clean up
- ShutdownTapi();
-
- CoUninitialize();
-
- return 1;
- }
-
-
- //////////////////////////////////////////////////////////////
- // InitializeTapi
- //
- // Various initializations
- ///////////////////////////////////////////////////////////////
- HRESULT
- InitializeTapi()
- {
- HRESULT hr;
- LPWSTR psz;
-
-
- // cocreate the TAPI object
- hr = CoCreateInstance(
- CLSID_TAPI,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_ITTAPI,
- (LPVOID *)&gpTapi
- );
-
- if (hr != S_OK)
- {
- DoMessage(L"CoCreateInstance on TAPI failed");
- return hr;
- }
-
- // call initialize. this must be called before
- // any other tapi functions are called.
- hr = gpTapi->Initialize();
-
- if (S_OK != hr)
- {
- DoMessage(L"TAPI failed to initialize");
-
- gpTapi->Release();
- gpTapi = NULL;
-
- return hr;
- }
-
-
- // convert the TAPIMEDIATYPEs to BSTRs for
- // convenience throughout the program
-
- StringFromIID( TAPIMEDIATYPE_AudioIn, &psz );
- gbstrAudioIn = SysAllocString( psz );
- CoTaskMemFree( psz );
-
- StringFromIID( TAPIMEDIATYPE_AudioOut, &psz );
- gbstrAudioOut = SysAllocString( psz );
- CoTaskMemFree( psz );
-
- StringFromIID( TAPIMEDIATYPE_VideoIn, &psz );
- gbstrVideoIn = SysAllocString( psz );
- CoTaskMemFree( psz );
-
- StringFromIID( TAPIMEDIATYPE_VideoOut, &psz );
- gbstrVideoOut = SysAllocString( psz );
- CoTaskMemFree( psz );
-
- // find all address objects that
- // we will use to listen for calls on
- hr = ListenOnAddresses();
-
- if (S_OK != hr)
- {
- DoMessage(L"Could not find any addresses to listen on");
-
- gpTapi->Release();
- gpTapi = NULL;
-
- return hr;
- }
-
- return S_OK;
-
- }
-
-
- ///////////////////////////////////////////////////////////////
- // ShutdownTapi
- ///////////////////////////////////////////////////////////////
- void
- ShutdownTapi()
- {
- CCallNotificationPtrList::iterator i;
- // if there is still a call,
- // release it
- if (NULL != gpCall)
- {
- gpCall->Release();
- gpCall = NULL;
- }
-
-
- // Release all CallNotification objects
- for (
- i = gpCallNotificationList.begin();
- i != gpCallNotificationList.end();
- i++
- )
- {
-
- (*i)->Shutdown();
-
- // At this point, we should call Unadvise on
- // the ConnectionPoint. However, TAPI 3.0
- // does not support Unadvise for the ITCallNotification
- // interface. So, here we just release the object
- (*i)->Release();
- }
-
- // release main object.
- if (NULL != gpTapi)
- {
- gpTapi->Shutdown();
- gpTapi->Release();
- }
-
- // free the BSTRs
- SysFreeString( gbstrAudioIn );
- SysFreeString( gbstrAudioOut );
- SysFreeString( gbstrVideoIn );
- SysFreeString( gbstrVideoOut );
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // MainDlgProc
- ///////////////////////////////////////////////////////////////////////////
- BOOL
- CALLBACK
- MainDialogProc(
- HWND hDlg,
- UINT uMsg,
- WPARAM wParam,
- LPARAM lParam
- )
- {
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- // set up dialog
- ghDlg = hDlg;
-
- DisableButton( IDC_ANSWER );
- DisableButton( IDC_DISCONNECT );
-
- SetStatusMessage( L"Waiting for a call..." );
-
- return 0;
- }
-
- case WM_COMMAND:
- {
- if ( LOWORD(wParam) == IDCANCEL )
- {
- // quit
- EndDialog( hDlg, 0 );
-
- return 1;
- }
-
- switch ( LOWORD(wParam) )
- {
- // dial request
- case IDC_ANSWER:
- {
- SetStatusMessage(L"Answering...");
- // answer the call
- if ( S_OK == AnswerTheCall() )
- {
- SetStatusMessage(L"Connected");
-
- EnableButton( IDC_DISCONNECT );
- DisableButton( IDC_ANSWER );
- }
- else
- {
- DisableButton( IDC_ANSWER );
- DoMessage(L"Answer failed");
- SetStatusMessage(L"Waiting for a call...");
- }
-
- return 1;
- }
-
- // disconnect request
- case IDC_DISCONNECT:
- {
- SetStatusMessage(L"Disconnecting...");
- // disconnect
- if (S_OK != DisconnectTheCall())
- {
- DoMessage(L"Disconnect failed");
- }
-
- return 1;
- }
-
- // disconnected notification
- case IDC_DISCONNECTED:
- {
- // release
- ReleaseTheCall();
-
- EnableButton( IDOK );
- DisableButton( IDC_DISCONNECT );
-
- SetStatusMessage(L"Waiting for a call...");
-
- return 1;
- }
- default:
-
- return 0;
- }
- }
- default:
-
- return 0;
- }
- }
-
-
- ////////////////////////////////////////////////////////////////////////
- // ListenOnAddresses
- //
- // This procedure will find all addresses that support audioin and audioout
- // and will call ListenOnThisAddress to start listening on it.
- ////////////////////////////////////////////////////////////////////////
- HRESULT
- ListenOnAddresses()
- {
- HRESULT hr = S_OK;
- IEnumAddress * pEnumAddress;
- ITAddress * pAddress;
- ITMediaSupport * pMediaSupport;
- VARIANT_BOOL bSupport;
-
- // enumerate the addresses
- hr = gpTapi->_EnumerateAddresses( &pEnumAddress );
-
- if (S_OK != hr)
- {
- return hr;
- }
-
- while ( TRUE )
- {
- // get the next address
- hr = pEnumAddress->Next( 1, &pAddress, NULL );
-
- if (S_OK != hr)
- {
- break;
- }
-
- pAddress->QueryInterface( IID_ITMediaSupport, (void **)&pMediaSupport );
-
- // does it support AudioIn?
- pMediaSupport->QueryMediaType(
- gbstrAudioIn,
- &bSupport
- );
-
- if (bSupport)
- {
- // does it also support AudioOut?
- pMediaSupport->QueryMediaType(
- gbstrAudioOut,
- &bSupport
- );
-
- if (bSupport)
- {
- // listen
- hr = ListenOnThisAddress( pAddress );
- if (S_OK != hr)
- {
- DoMessage(L"Listen failed on an address");
- }
- }
- }
-
- pMediaSupport->Release();
- pAddress->Release();
- }
-
- pEnumAddress->Release();
-
- return S_OK;
- }
-
-
- ///////////////////////////////////////////////////////////////////
- // ListenOnThisAddress
- //
- // Perform the steps involved in setting up an address to listen
- // for calls. Setting up an application to listen for calls is a two
- // step process.
- //
- // First, the app must call RegisterCallTypes
- // on the address that it wants calls on
- //
- // Second, it must register it's implementation of ITCallNotification
- // with the address. Registration is done via COM's ConnectionPoint
- // methods. See the COM documentation for more informations on
- // ConnectionPoints
- //
- ///////////////////////////////////////////////////////////////////
- HRESULT
- ListenOnThisAddress(
- ITAddress * pAddress
- )
- {
- HRESULT hr = S_OK;
- IConnectionPointContainer * pCPC;
- IConnectionPoint * pCP;
- CCallNotification * pCallNotification;
- DWORD dwCookie;
- VARIANT var;
-
- // RegisterCallTypes takes an array (in a variant) of
- // MediaTypes for the address to listen for.
- // If NULL is specified for the array, that means to listen
- // for all the media types that the address supports.
- //
- // Since we already know the address supports audioin/audioout,
- // just tell it to listen for all types. Also, we will tell
- // it that we are only interested in being the owner of calls,
- // not monitoring
-
- VariantInit( &var );
- var.vt = VT_ARRAY;
- var.parray = NULL;
-
- hr = pAddress->RegisterCallTypes(
- FALSE,
- TRUE, // Want to be owner
- FALSE, // Don't want to be monitor
- var // mediatypes
- );
-
- if (S_OK != hr)
- {
- return hr;
- }
-
- // now we need to register our outgoing interface through
- // the ConnectionPoint methods.
-
- // First we create our CCallNotification object
- pCallNotification = new CCallNotification;
-
- if (NULL == pCallNotification)
- {
- return E_OUTOFMEMORY;
- }
-
- // initialize the object
- hr = pCallNotification->Initialize( pAddress );
-
- if (S_OK != hr)
- {
- pCallNotification->Release();
- return hr;
- }
-
- // get the IConnectionPointContainer interface
- // from the address object
- hr = pAddress->QueryInterface(
- IID_IConnectionPointContainer,
- (void **)&pCPC
- );
-
- if (S_OK != hr)
- {
- pCallNotification->Release();
- pCallNotification = NULL;
- return hr;
- }
-
- // find the ConnectionPoint we are interested in
- hr = pCPC->FindConnectionPoint( IID_ITCallNotification, &pCP );
-
- pCPC->Release();
-
- if (S_OK != hr)
- {
- pCallNotification->Release();
- pCallNotification = NULL;
- return hr;
- }
-
- // call the advise function
- //
- // if this function succeeds, the address will start
- // listening for calls.
- hr = pCP->Advise(
- (IUnknown *)pCallNotification,
- &dwCookie
- );
-
- pCP->Release();
-
- if (S_OK != hr)
- {
- pCallNotification->Release();
- pCallNotification = NULL;
- return hr;
- }
-
- // save the notification object
- // note that normally you would want
- // to save the dwCookie as well. Refer
- // to the COM ConnectionPoint documentation
- // for more details.
- gpCallNotificationList.push_back( pCallNotification );
-
- return S_OK;
- }
-
- /////////////////////////////////////////////////////////
- // GetMediaTerminal
- //
- // Creates a MediaTerminal for the bstrMediaType passed
- // in, using the default terminal for the bstrMediaType
- //
- /////////////////////////////////////////////////////////
- HRESULT
- GetMediaTerminal(
- ITAddress * pAddress,
- BSTR bstrMediaType,
- ITMediaTerminal ** ppMediaTerminal
- )
- {
- HRESULT hr = S_OK;
- ITTerminalSupport * pTerminalSupport;
- ITTerminal * pTerminal;
-
- // get the terminal support interface
- pAddress->QueryInterface( IID_ITTerminalSupport, (void **)&pTerminalSupport );
-
- // get the default terminal for MediaType
- hr = pTerminalSupport->GetDefaultTerminal(
- bstrMediaType,
- &pTerminal
- );
-
-
- pTerminalSupport->Release();
-
- if (S_OK != hr)
- {
- return hr;
- }
-
- // Create a media terminal for MediaType
- // Use the default terminal we just got
- hr = gpTapi->CreateMediaTerminal(
- bstrMediaType,
- pTerminal,
- ppMediaTerminal
- );
-
- pTerminal->Release();
-
- if (S_OK != hr)
- {
- return hr;
- }
-
- return S_OK;
-
- }
-
- /////////////////////////////////////////////////////////
- // GetVideoInMediaTerminal
- //
- // Creates a MediaTerminal for the VideoIn mediatype
- // This is a dynamic terminal type.
- //
- /////////////////////////////////////////////////////////
- HRESULT
- GetVideoInMediaTerminal(
- ITAddress * pAddress,
- ITMediaTerminal ** ppMediaTerminal
- )
- {
- HRESULT hr = S_OK;
- ITTerminalSupport * pTerminalSupport;
- ITTerminal * pTerminal;
-
- // get the terminal support interface
- pAddress->QueryInterface( IID_ITTerminalSupport, (void **)&pTerminalSupport );
-
- BSTR bstrTerminalClass;
- LPOLESTR lpTerminalClass;
-
- StringFromIID(
- CLSID_VideoWindowTerm,
- &lpTerminalClass
- );
-
- bstrTerminalClass = SysAllocString ( lpTerminalClass );
-
- CoTaskMemFree( lpTerminalClass );
-
- hr = pTerminalSupport->CreateTerminal(
- bstrTerminalClass,
- &pTerminal
- );
-
- SysFreeString( bstrTerminalClass );
- pTerminalSupport->Release();
-
- if (FAILED(hr))
- {
- return hr;
- }
-
- // Create a media terminal for MediaType
- // Use the default terminal we just got
- hr = gpTapi->CreateMediaTerminal(
- gbstrVideoIn,
- pTerminal,
- ppMediaTerminal
- );
-
- pTerminal->Release();
-
- if (S_OK != hr)
- {
- return hr;
- }
-
- return S_OK;
-
- }
-
- /////////////////////////////////////////////////////////////////
- // CreateMediaTerminals
- //
- // Create audioin and audioout terminals. Videoin and videoout terminals
- // are created only when the address supports them.
- //
- // This function assumes that ppMediaTerminals has a size no less than four.
- /////////////////////////////////////////////////////////////////
- HRESULT
- CreateMediaTerminals(
- ITAddress *pAddress,
- ITMediaTerminal ** ppMediaTerminals,
- PLONG pNumMediaTerminals
- )
- {
- int count = 0;
- HRESULT hr;
-
- // get the mediaterminal for audioin
- hr = GetMediaTerminal(
- pAddress,
- gbstrAudioIn,
- &ppMediaTerminals[count]
- );
-
- if (S_OK != hr)
- {
- return hr;
- }
-
- count ++;
-
- // get the mediaterminal for audioout
- hr = GetMediaTerminal(
- pAddress,
- gbstrAudioOut,
- &ppMediaTerminals[count]
- );
-
- if (S_OK != hr)
- {
- ppMediaTerminals[0]->Release();
- return hr;
- }
-
- count ++;
-
- // Find out if the address supports video.
- ITMediaSupport *pMediaSupport;
- VARIANT_BOOL bSupport;
-
- pAddress->QueryInterface( IID_ITMediaSupport, (void **)&pMediaSupport );
-
- // does it support VideoIn?
- pMediaSupport->QueryMediaType(
- gbstrVideoIn,
- &bSupport
- );
-
- if (bSupport)
- {
- // get the mediaterminal for VideoIn
- hr = GetVideoInMediaTerminal(
- pAddress,
- &ppMediaTerminals[count]
- );
-
- if (S_OK == hr)
- {
- count ++;
- }
-
- // does it also support VideoOut?
- pMediaSupport->QueryMediaType(
- gbstrVideoOut,
- &bSupport
- );
-
- if (bSupport)
- {
- // get the mediaterminal for Videoout
- hr = GetMediaTerminal(
- pAddress,
- gbstrVideoOut,
- &ppMediaTerminals[count]
- );
-
- if (S_OK == hr)
- {
- count ++;
- }
- }
- }
-
- pMediaSupport->Release();
-
- *pNumMediaTerminals = count;
-
- return S_OK;
- }
-
- /////////////////////////////////////////////////////////////////
- // CreateMediaTerminalSafeArray
- //
- /////////////////////////////////////////////////////////////////
- SAFEARRAY *
- CreateMediaTerminalSafeArray(
- ITMediaTerminal ** ppMediaTerminals,
- LONG nNumMediaTerminals
- )
- {
- SAFEARRAY * psa;
- SAFEARRAYBOUND sabound[1];
-
- // create a safearray with two elements
- // to pass the mediaterminals to tapi
- sabound[0].lLbound = 0;
- sabound[0].cElements = nNumMediaTerminals;
-
- psa = SafeArrayCreate(
- VT_UNKNOWN,
- 1,
- sabound
- );
-
- if (NULL != psa)
- {
- // save them in the safearray
- for (long i = 0; i < nNumMediaTerminals; i ++)
- {
- SafeArrayPutElement(
- psa,
- &i,
- ppMediaTerminals[i]
- );
- }
- }
- return psa;
- }
-
- /////////////////////////////////////////////////////////////////
- // ReleaseMediaTerminals
- //
- /////////////////////////////////////////////////////////////////
- void
- ReleaseMediaTerminals(
- ITMediaTerminal ** ppMediaTerminals,
- LONG nNumMediaTerminals
- )
- {
- for (long i = 0; i < nNumMediaTerminals; i ++)
- {
- if (ppMediaTerminals[i])
- {
- ppMediaTerminals[i]->Release();
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////
- // Answer the call
- /////////////////////////////////////////////////////////////////////
- HRESULT
- AnswerTheCall()
- {
- HRESULT hr;
- ITCallInfo * pCallInfo;
- ITAddress * pAddress;
- ITMediaTerminal * ppMediaTerminals[MAXTERMINALS];
- long nNumMediaTerminals = MAXTERMINALS;
- SAFEARRAY * psa;
-
-
-
- if (NULL == gpCall)
- {
- return E_UNEXPECTED;
- }
-
-
- // get the address object of this call
- gpCall->QueryInterface( IID_ITCallInfo, (void**)&pCallInfo );
- pCallInfo->get_Address( &pAddress );
- pCallInfo->Release();
-
-
- // create the media terminals for this call
- hr = CreateMediaTerminals(
- pAddress,
- ppMediaTerminals,
- &nNumMediaTerminals
- );
-
-
- // release the address
- pAddress->Release();
-
-
- if (S_OK != hr)
- {
- gpCall->Release();
- gpCall = NULL;
- return hr;
- }
-
- psa = CreateMediaTerminalSafeArray(ppMediaTerminals, nNumMediaTerminals);
-
- if (S_OK != hr)
- {
- gpCall->Release();
- gpCall = NULL;
- ReleaseMediaTerminals(ppMediaTerminals, nNumMediaTerminals);
- return hr;
- }
-
- // put the safearray in a variant
- VARIANT var;
- VariantInit(&var);
- var.vt = VT_ARRAY;
- var.parray = psa;
-
- // call SelectMediaTerminals
- hr = gpCall->SelectMediaTerminals(
- var
- );
-
- ReleaseMediaTerminals(ppMediaTerminals, nNumMediaTerminals);
-
- SafeArrayDestroy( psa );
-
- if (S_OK != hr)
- {
- gpCall->Release();
- gpCall = NULL;
- return hr;
- }
-
- // answer the call
- hr = gpCall->Answer();
-
- return hr;
- }
-
- //////////////////////////////////////////////////////////////////////
- // DisconnectTheCall
- //
- // Disconnects the call
- //////////////////////////////////////////////////////////////////////
- HRESULT
- DisconnectTheCall()
- {
- HRESULT hr = S_OK;
-
- if (NULL != gpCall)
- {
- hr = gpCall->Disconnect( DC_NORMAL );
-
- gpCall->Release();
- gpCall = NULL;
-
- return hr;
- }
-
- return S_FALSE;
- }
-
- //////////////////////////////////////////////////////////////////////
- // ReleaseTheCall
- //
- // Releases the call
- //////////////////////////////////////////////////////////////////////
- void
- ReleaseTheCall()
- {
- if (NULL != gpCall)
- {
- gpCall->Release();
- gpCall = NULL;
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////
- //
- // HELPER FUNCTIONS
- //
- ///////////////////////////////////////////////////////////////////
-
-
- ///////////////////////////////////////////////////////////////////
- // DoMessage
- ///////////////////////////////////////////////////////////////////
- void
- DoMessage(
- LPWSTR pszMessage
- )
- {
- MessageBox(
- ghDlg,
- pszMessage,
- gszTapi30,
- MB_OK
- );
- }
-
-
- //////////////////////////////////////////////////////////////////
- // SetStatusMessage
- //////////////////////////////////////////////////////////////////
- void
- SetStatusMessage(
- LPWSTR pszMessage
- )
- {
- SetDlgItemText(
- ghDlg,
- IDC_STATUS,
- pszMessage
- );
- }
-
- ///////////////////////////////////////////////////////////////
- // EnableButton
- //
- // Enable, make default, and setfocus to a button
- ///////////////////////////////////////////////////////////////
- void
- EnableButton(
- int ID
- )
- {
- SendDlgItemMessage(
- ghDlg,
- ID,
- BM_SETSTYLE,
- BS_DEFPUSHBUTTON,
- 0
- );
- EnableWindow(
- GetDlgItem( ghDlg, ID ),
- TRUE
- );
- SetFocus(
- GetDlgItem( ghDlg, ID )
- );
- }
-
- //////////////////////////////////////////////////////////////
- // DisableButton
- //
- // Disable a button
- //////////////////////////////////////////////////////////////
- void
- DisableButton(
- int ID
- )
- {
- SendDlgItemMessage(
- ghDlg,
- ID,
- BM_SETSTYLE,
- BS_PUSHBUTTON,
- 0
- );
- EnableWindow(
- GetDlgItem( ghDlg, ID ),
- FALSE
- );
- }
-
-
-
-