#define UNICODE
#include <windows.h>
#include <tapi3.h>
#include "resource.h"
//////////////////////////////////////////////////////////
// T3OUT.EXE
//
// Example of making an outgoing call with TAPI 3.0
//
// This application will allow a user to make a call
// by using TAPI 3.0. The application will simply look
// for the first TAPI line that support Audio, and can
// dial a phone number. It will then use that line to
// make calls.
//
// This application does not handle incoming calls, and
// does not process incoming messages.
//
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// Constants
//////////////////////////////////////////////////////////
const DWORD ADDRESSLENGTH = 128;
const DWORD MAXTERMINALS = 5;
const WCHAR * const gszTapi30 = L"TAPI 3.0 Outgoing Call Sample";
const WCHAR * const gszConferenceName = L"Conference Name";
const WCHAR * const gszEmailName = L"Email Name";
const WCHAR * const gszMachineName = L"Machine Name";
const WCHAR * const gszPhoneNumber = L"Phone Number";
const WCHAR * const gszIPAddress = L"IP Address";
//////////////////////////////////////////////////////////
// GLOBALS
//////////////////////////////////////////////////////////
HINSTANCE ghInst;
HWND ghDlg = NULL;
ITTAPI * gpTapi;
ITAddress * gpAddress;
ITBasicCallControl * gpCall;
BSTR gbstrAudioIn;
BSTR gbstrAudioOut;
BSTR gbstrVideoIn;
BSTR gbstrVideoOut;
//////////////////////////////////////////////////////////
// PROTOTYPES
//////////////////////////////////////////////////////////
BOOL
CALLBACK
MainDialogProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
HRESULT
FindAnAddress(
DWORD dwAddressType
);
HRESULT
GetMediaTerminal(
BSTR bstrMedia,
ITMediaTerminal ** ppMediaTerminal
);
HRESULT
GetVideoInMediaTerminal(
ITMediaTerminal ** ppMediaTerminal
);
HRESULT
MakeTheCall(
DWORD dwAddressType,
PWCHAR szAddressToCall
);
HRESULT
DisconnectTheCall();
void
DoMessage(
LPWSTR pszMessage
);
HRESULT
InitializeTapi();
void
ShutdownTapi();
void
EnableButton(
HWND hDlg,
int ID
);
void
DisableButton(
HWND hDlg,
int ID
);
//////////////////////////////////////////////////////////
// WinMain
//////////////////////////////////////////////////////////
int
WINAPI
WinMain(
HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpCmdLine,
int nCmdShow
)
{
ghInst = hInst;
// need to coinit
if (!SUCCEEDED(CoInitialize(NULL)))
{
return 0;
}
if (S_OK != InitializeTapi())
{
return 0;
}
// everything is initialized, so
// start the main dialog box
DialogBox(
ghInst,
MAKEINTRESOURCE(IDD_MAINDLG),
NULL,
MainDialogProc
);
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 );
return S_OK;
}
///////////////////////////////////////////////////////////////
// ShutdownTapi
///////////////////////////////////////////////////////////////
void
ShutdownTapi()
{
// if there is still a call,
// release it
if (NULL != gpCall)
{
gpCall->Release();
gpCall = NULL;
}
// if we have an address object
// release it
if (NULL != gpAddress)
{
gpAddress->Release();
}
// release main object.
if (NULL != gpTapi)
{
gpTapi->Shutdown();
gpTapi->Release();
}
SysFreeString( gbstrAudioIn );
SysFreeString( gbstrAudioOut );
SysFreeString( gbstrVideoIn );
SysFreeString( gbstrVideoOut );
}
///////////////////////////////////////////////////////////////////////////
// InitAddressTypeComboBox
//
// Put address type string in the combo box
// and save the addresstype with the string
//
///////////////////////////////////////////////////////////////////////////
void
InitAddressTypeComboBox(
HWND hComboBox
)
{
int i;
i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszConferenceName );
SendMessage(
hComboBox,
CB_SETITEMDATA ,
i,
(long)T3_ADDRESSTYPE_CONFERENCENAME
);
i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszEmailName );
SendMessage(
hComboBox,
CB_SETITEMDATA ,
i,
(long)T3_ADDRESSTYPE_EMAILNAME
);
i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszMachineName );
SendMessage(
hComboBox,
CB_SETITEMDATA ,
i,
(long)T3_ADDRESSTYPE_DOMAINNAME
);
i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszPhoneNumber );
SendMessage(
hComboBox,
CB_SETITEMDATA ,
i,
(long)T3_ADDRESSTYPE_PHONENUMBER
);
SendMessage( hComboBox, CB_SETCURSEL, i, 0 );
i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszIPAddress );
SendMessage(
hComboBox,
CB_SETITEMDATA ,
i,
(long)T3_ADDRESSTYPE_IPADDRESS
);
}
///////////////////////////////////////////////////////////////////////////
// MainDlgProc
///////////////////////////////////////////////////////////////////////////
BOOL
CALLBACK
MainDialogProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND hComboBox;
// set up dialog
ghDlg = hDlg;
EnableButton( hDlg, IDOK );
DisableButton( hDlg, IDC_DISCONNECT );
hComboBox = GetDlgItem( hDlg, IDC_ADDRESSTYPE );
InitAddressTypeComboBox(hComboBox);
SetFocus( hComboBox );
return 0;
}
case WM_COMMAND:
{
if ( LOWORD(wParam) == IDCANCEL )
{
// quit
EndDialog( hDlg, 0 );
return 1;
}
// dial request
if ( LOWORD(wParam) == IDOK )
{
HWND hComboBox;
DWORD dwIndex;
DWORD dwAddressType;
WCHAR szAddressToCall[ADDRESSLENGTH];
// get the address type the user selected.
hComboBox = GetDlgItem( hDlg, IDC_ADDRESSTYPE );
dwIndex = SendMessage( hComboBox, CB_GETCURSEL, 0, 0 );
dwAddressType = SendMessage(
hComboBox,
CB_GETITEMDATA,
dwIndex,
0
);
// get the address the user wants to call
GetDlgItemText(
hDlg,
IDC_ADDRESS,
szAddressToCall,
ADDRESSLENGTH
);
// make the call
if ( S_OK == MakeTheCall(dwAddressType, szAddressToCall) )
{
EnableButton( hDlg, IDC_DISCONNECT );
DisableButton( hDlg, IDOK );
}
else
{
DoMessage(L"The call failed to connect");
}
return 1;
}
// disconnect requestion
if ( LOWORD( wParam ) == IDC_DISCONNECT )
{
// disconnect
if (S_OK == DisconnectTheCall())
{
EnableButton( hDlg, IDOK );
DisableButton( hDlg, IDC_DISCONNECT );
}
else
{
DoMessage(L"The call failed to disconnect");
}
return 1;
}
return 0;
}
default:
return 0;
}
}
////////////////////////////////////////////////////////////////////////
// FindAnAddress
//
// Finds an address object that this application will use to make calls on.
//
// This function finds an address that supports the addresstype passed
// in, as well as the audioin and audioout media types.
//
// Return Value
// S_OK if it finds an address
// S_FALSE if it does not find an address
////////////////////////////////////////////////////////////////////////
HRESULT
FindAnAddress(
DWORD dwAddressType
)
{
HRESULT hr = S_OK;
BOOL bFoundAddress = FALSE;
IEnumAddress * pEnumAddress;
ITAddress * pAddress;
IEnumAddressType * pEnumAddressTypes;
DWORD dwType;
// if we have an address object
// release it
if (NULL != gpAddress)
{
gpAddress->Release();
gpAddress = NULL;
}
// enumerate the addresses
hr = gpTapi->_EnumerateAddresses( &pEnumAddress );
if (S_OK != hr)
{
return hr;
}
while ( !bFoundAddress )
{
// get the next address
hr = pEnumAddress->Next( 1, &pAddress, NULL );
if (S_OK != hr)
{
break;
}
// enumerate the address types that
// this address supports
hr = pAddress->_EnumerateAddressType( &pEnumAddressTypes );
if (S_OK != hr)
{
pAddress->Release();
continue;
}
while (TRUE)
{
ITMediaSupport * pMediaSupport;
VARIANT_BOOL bSupport;
// get the next address type
hr = pEnumAddressTypes->Next( 1, &dwType, NULL );
if (S_OK != hr)
{
break;
}
// is the type we are looking for?
if ( dwAddressType == dwType )
{
// yes
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)
{
// save
pMediaSupport->Release();
gpAddress = pAddress;
gpAddress->AddRef();
bFoundAddress = TRUE;
break;
}
}
pMediaSupport->Release();
}
}
pAddress->Release();
pEnumAddressTypes->Release();
}
pEnumAddress->Release();
if (!bFoundAddress)
{
return S_FALSE;
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// CreateMediaTerminals
//
// Create audioin and audioout terminals.
//
// If the address also supports video, create
// Videoin and videoout terminals, too.
//
// This function assumes that ppMediaTerminals has a size no less than four.
/////////////////////////////////////////////////////////////////
HRESULT
CreateMediaTerminals(
ITMediaTerminal ** ppMediaTerminals,
PLONG pNumMediaTerminals
)
{
int count = 0;
HRESULT hr;
// get the mediaterminal for audioin
hr = GetMediaTerminal(
gbstrAudioIn,
&ppMediaTerminals[count]
);
if (S_OK != hr)
{
return hr;
}
count ++;
// get the mediaterminal for audioout
hr = GetMediaTerminal(
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;
gpAddress->QueryInterface( IID_ITMediaSupport, (void **)&pMediaSupport );
// does it support VideoIn?
pMediaSupport->QueryMediaType(
gbstrVideoIn,
&bSupport
);
if (bSupport)
{
// get the mediaterminal for VideoIn
hr = GetVideoInMediaTerminal(
&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(
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();
}
}
}
/////////////////////////////////////////////////////////////////
// MakeTheCall
//
// Sets up and makes a call
/////////////////////////////////////////////////////////////////
HRESULT
MakeTheCall(
DWORD dwAddressType,
PWCHAR szAddressToCall
)
{
HRESULT hr = S_OK;
ITMediaTerminal * ppMediaTerminals[MAXTERMINALS];
long nNumMediaTerminals = MAXTERMINALS;
SAFEARRAY * psa;
VARIANT var;
BSTR bstrAddressToCall;
// find an address object that
// we will use to make calls on
hr = FindAnAddress(dwAddressType);
if (S_OK != hr)
{
DoMessage(L"Could not find an address to make a phone call on");
return hr;
}
bstrAddressToCall = SysAllocString( szAddressToCall );
hr = gpAddress->CreateCall( bstrAddressToCall, &gpCall );
SysFreeString ( bstrAddressToCall );
if (S_OK != hr)
{
return hr;
}
hr = CreateMediaTerminals(ppMediaTerminals, &nNumMediaTerminals);
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
VariantInit(&var);
var.vt = VT_ARRAY;
var.parray = psa;
// call SelectMediaTerminals
hr = gpCall->SelectMediaTerminals( var );
ReleaseMediaTerminals(ppMediaTerminals, nNumMediaTerminals);
SafeArrayDestroy( psa );
if (S_OK != hr)
{
return hr;
}
// We're now ready to call connect.
//
// the TRUE parameter indicates that this
// call is sychronous - that is, it won't
// return until the call is in the connected
// state (or fails to connect)
// Since this is called in the UI thread,
// this means that the app will appear
// to hang until this function returns.
// Some TAPI service providers may take a long
// time for a call to reach the connected state.
hr = gpCall->Connect( TRUE );
if (S_OK != hr)
{
gpCall->Release();
gpCall = NULL;
return hr;
}
return hr;
}
/////////////////////////////////////////////////////////
// GetMediaTerminal
//
// Creates a MediaTerminal for the bstrMediaType passed
// in, using the default terminal for the bstrMediaType
//
/////////////////////////////////////////////////////////
HRESULT
GetMediaTerminal(
BSTR bstrMediaType,
ITMediaTerminal ** ppMediaTerminal
)
{
HRESULT hr = S_OK;
ITTerminalSupport * pTerminalSupport;
ITTerminal * pTerminal;
// get the terminal support interface
gpAddress->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(
ITMediaTerminal ** ppMediaTerminal
)
{
HRESULT hr = S_OK;
ITTerminalSupport * pTerminalSupport;
ITTerminal * pTerminal;
// get the terminal support interface
gpAddress->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;
}
//////////////////////////////////////////////////////////////////////
// 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;
}
///////////////////////////////////////////////////////////////////
//
// HELPER FUNCTIONS
//
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// DoMessage
///////////////////////////////////////////////////////////////////
void
DoMessage(
LPWSTR pszMessage
)
{
MessageBox(
ghDlg,
pszMessage,
gszTapi30,
MB_OK
);
}
///////////////////////////////////////////////////////////////
// EnableButton
//
// Enable, make default, and setfocus to a button
///////////////////////////////////////////////////////////////
void
EnableButton(
HWND hDlg,
int ID
)
{
SendDlgItemMessage(
hDlg,
ID,
BM_SETSTYLE,
BS_DEFPUSHBUTTON,
0
);
EnableWindow(
GetDlgItem( hDlg, ID ),
TRUE
);
SetFocus(
GetDlgItem( hDlg, ID )
);
}
//////////////////////////////////////////////////////////////
// DisableButton
//
// Disable a button
//////////////////////////////////////////////////////////////
void
DisableButton(
HWND hDlg,
int ID
)
{
SendDlgItemMessage(
hDlg,
ID,
BM_SETSTYLE,
BS_PUSHBUTTON,
0
);
EnableWindow(
GetDlgItem( hDlg, ID ),
FALSE
);
}