windows-nt/Source/XPSP1/NT/multimedia/media/dplayx/dplay/serial/modem.c
2020-09-26 16:20:57 +08:00

1166 lines
32 KiB
C

/*==========================================================================
*
* Copyright (C) 1996-1999 Microsoft Corporation. All Rights Reserved.
*
* File: modem.c
* Content: Routines for modem I/O
* History:
* Date By Reason
* ==== == ======
* 6/10/96 kipo created it
* 6/22/96 kipo added support for EnumConnectionData(); dim "OK" button
* until user types at least one character.
* 6/25/96 kipo updated for DPADDRESS
* 7/08/96 kipo added support for new dialogs
* 7/13/96 kipo added GetModemAddress()
* 7/16/96 kipo changed address types to be GUIDs instead of 4CC
* 8/10/96 kipo added support for dialing location
* 8/15/96 kipo commented out support for dialing location
* 9/04/96 dereks fixed focus in dial/answer dialogs
* 1/06/97 kipo updated for objects
* 2/11/97 kipo pass player flags to GetAddress()
* 2/18/97 kipo allow multiple instances of service provider
* 3/04/97 kipo close com port handle when deallocating call; use string
* table for modem strings; updated debug output.
* 3/17/97 kipo added support for Unicode phone numbers
* 3/24/97 kipo added support for specifying which modem to use
* 4/08/97 kipo added support for separate modem and serial baud rates
* 5/07/97 kipo added support for modem choice list
* 5/23/97 kipo added support return status codes
* 5/25/97 kipo use DPERR_CONNECTING error to return status; set focus
* on cancel button in status window
* 6/03/97 kipo really make the cancel button work with return
* 2/01/98 kipo Display an error string in status dialog if line goes
* idle while dialing. Fixes bug #15251
* 5/08/98 a-peterz #15251 - Better error state detection
* 10/13/99 johnkan #413516 - Mismatch between modem dialog selection and TAPI device ID
***************************************************************************/
#include <windows.h>
#include <windowsx.h>
#include "dplaysp.h"
#include "dputils.h"
#include "dial.h"
#include "dpf.h"
#include "resource.h"
// constants
enum {
PHONENUMBERSIZE = 200, // size of phone number string
MODEMNAMESIZE = 200, // size of modem name string
TEMPSTRINGSIZE = 300, // size of temporary strings
MODEMTIMEOUT = 30 * 1000, // milliseconds to wait for phone to connect
MODEMSLEEPTIME = 50, // milliseconds to sleep while waiting for modem
TIMERINTERVAL = 100,
MAXPHONENUMBERS = 10
};
// bit masks used to select connection actions
enum {
DIALCALL = (0 << 0), // make a call
ANSWERCALL = (1 << 0), // answer a call
NOSETTINGS = (0 << 1), // no phone settings are set
HAVESETTINGS = (1 << 1), // phone settings are set
STATUSDIALOG = (0 << 2), // show a connection status dialog
RETURNSTATUS = (1 << 2) // return status to app
};
#define MRU_SP_KEY L"Modem Connection For DirectPlay"
#define MRU_NUMBER_KEY L"Phone Number"
// structures
// modem object
typedef struct {
DPCOMPORT comPort; // base object globals
LPDPDIAL lpDial; // dialing globals
BOOL bHaveSettings; // set to TRUE if we have settings
BOOL bAnswering; // set to TRUE if we are answering
DWORD dwDeviceID; // device id to use
DWORD dwLocation; // location to use
TCHAR szPhoneNumber[PHONENUMBERSIZE]; // phone number to use
} DPMODEM, *LPDPMODEM;
// globals
// this is defined in dllmain.c
extern HINSTANCE ghInstance;
// this is defined in dpserial.c
extern GUID DPMODEM_GUID;
// prototypes
static HRESULT DisposeModem(LPDPCOMPORT baseObject);
static HRESULT ConnectModem(LPDPCOMPORT baseObject, BOOL bWaitForConnection, BOOL bReturnStatus);
static HRESULT DisconnectModem(LPDPCOMPORT baseObject);
static HRESULT GetModemBaudRate(LPDPCOMPORT baseObject, LPDWORD lpdwBaudRate);
static HRESULT GetModemAddress(LPDPCOMPORT baseObject, DWORD dwPlayerFlags,
LPVOID lpAddress, LPDWORD lpdwAddressSize);
static BOOL FAR PASCAL EnumAddressData(REFGUID lpguidDataType, DWORD dwDataSize,
LPCVOID lpData, LPVOID lpContext);
static HRESULT GetModemAddressChoices(LPDPCOMPORT baseObject,
LPVOID lpAddress, LPDWORD lpdwAddressSize);
static BOOL FAR PASCAL EnumMRUPhoneNumbers(LPCVOID lpData, DWORD dwDataSize, LPVOID lpContext);
static void UpdateButtons(HWND hWnd);
BOOL DoDialSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
BOOL DoDial(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
BOOL DoAnswerSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
BOOL DoAnswer(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
HRESULT DoDialStatus(LPDPMODEM globals);
HRESULT DoAnswerStatus(LPDPMODEM globals);
/*
* NewModem
*
* Create new modem object. Open TAPI and verify there are lines available.
*/
HRESULT NewModem(LPVOID lpConnectionData, DWORD dwConnectionDataSize,
LPDIRECTPLAYSP lpDPlay, LPREADROUTINE lpReadRoutine,
LPDPCOMPORT *storage)
{
LPDPCOMPORT baseObject;
LPDPMODEM globals;
LINERESULT lResult;
HRESULT hr;
// create base object with enough space for our globals
hr = NewComPort(sizeof(DPMODEM), lpDPlay, lpReadRoutine, &baseObject);
if FAILED(hr)
return (hr);
// fill in methods we implement
baseObject->Dispose = DisposeModem;
baseObject->Connect = ConnectModem;
baseObject->Disconnect = DisconnectModem;
baseObject->GetBaudRate = GetModemBaudRate;
baseObject->GetAddress = GetModemAddress;
baseObject->GetAddressChoices = GetModemAddressChoices;
globals = (LPDPMODEM) baseObject;
// initialize TAPI
lResult = dialInitialize(ghInstance, TEXT("TapiSP"), (LPDPCOMPORT) globals, &globals->lpDial);
if (lResult)
{
hr = DPERR_UNAVAILABLE;
goto Failure;
}
// check for valid connection data
if (lpConnectionData)
{
baseObject->lpDPlay->lpVtbl->EnumAddress(baseObject->lpDPlay, EnumAddressData,
lpConnectionData, dwConnectionDataSize,
globals);
}
// return object pointer
*storage = baseObject;
return (DP_OK);
Failure:
DisposeModem(baseObject);
return (hr);
}
/*
* EnumConnectionData
*
* Search for valid connection data
*/
static BOOL FAR PASCAL EnumAddressData(REFGUID lpguidDataType, DWORD dwDataSize,
LPCVOID lpData, LPVOID lpContext)
{
LPDPMODEM globals = (LPDPMODEM) lpContext;
CHAR szModemName[MODEMNAMESIZE];
// this is an ANSI phone number
if ((IsEqualGUID(lpguidDataType, &DPAID_Phone)) &&
(dwDataSize) )
{
// make sure there is room (for terminating null too)
if (dwDataSize > (PHONENUMBERSIZE - 1))
dwDataSize = (PHONENUMBERSIZE - 1);
CopyMemory(globals->szPhoneNumber, lpData, dwDataSize);
globals->bHaveSettings = TRUE; // we have a phone number
}
// this is an UNICODE phone number
else if ((IsEqualGUID(lpguidDataType, &DPAID_PhoneW)) &&
(dwDataSize) )
{
if (WideToAnsi(globals->szPhoneNumber, (LPWSTR) lpData, PHONENUMBERSIZE))
globals->bHaveSettings = TRUE; // we have a phone number
}
// this is an ANSI modem name
else if ((IsEqualGUID(lpguidDataType, &DPAID_Modem)) &&
(dwDataSize) )
{
// search modem list for this name
if (dialGetDeviceIDFromName(globals->lpDial, lpData, &globals->dwDeviceID) == SUCCESS)
globals->bHaveSettings = TRUE; // can answer the phone
}
// this is a UNICODE modem name
else if ((IsEqualGUID(lpguidDataType, &DPAID_ModemW)) &&
(dwDataSize) )
{
// search modem list for this name
if (WideToAnsi(szModemName, (LPWSTR) lpData, MODEMNAMESIZE))
{
if (dialGetDeviceIDFromName(globals->lpDial, szModemName, &globals->dwDeviceID) == SUCCESS)
globals->bHaveSettings = TRUE; // we have a phone number
}
}
return (TRUE);
}
/*
* DisposeModem
*
* Dispose modem object.
*/
static HRESULT DisposeModem(LPDPCOMPORT baseObject)
{
LPDPMODEM globals = (LPDPMODEM) baseObject;
LPDPDIAL lpDial = globals->lpDial;
LINERESULT lResult;
// shut down modem
if (lpDial)
lResult = dialShutdown(lpDial);
// free object
GlobalFreePtr((HGLOBAL) baseObject);
return (DP_OK);
}
/*
* ConnectModem
*
* Dial number based on user settings.
*/
static HRESULT ConnectModem(LPDPCOMPORT baseObject,
BOOL bWaitForConnection, BOOL bReturnStatus)
{
LPDPMODEM globals = (LPDPMODEM) baseObject;
LPDPDIAL lpDial = globals->lpDial;
DWORD dwFeatures;
BOOL bResult;
HRESULT hr;
// dial object has not been created?
if (lpDial == NULL)
return (DPERR_INVALIDPARAM);
// are we already connected?
if (dialIsConnected(lpDial))
return (DP_OK);
// remember if we are answering or not
globals->bAnswering = bWaitForConnection;
dwFeatures = 0;
if (globals->bAnswering)
dwFeatures |= ANSWERCALL;
if (globals->bHaveSettings)
dwFeatures |= HAVESETTINGS;
if (bReturnStatus)
dwFeatures |= RETURNSTATUS;
hr = DP_OK;
switch (dwFeatures)
{
case (STATUSDIALOG | NOSETTINGS | DIALCALL):
bResult = DoDialSetup(ghInstance, GetForegroundWindow(), globals);
if (!bResult)
goto FAILURE;
globals->bHaveSettings = TRUE;
break;
case (STATUSDIALOG | NOSETTINGS | ANSWERCALL):
bResult = DoAnswerSetup(ghInstance, GetForegroundWindow(), globals);
if (!bResult)
goto FAILURE;
globals->bHaveSettings = TRUE;
break;
case (STATUSDIALOG | HAVESETTINGS | DIALCALL):
bResult = DoDial(ghInstance, GetForegroundWindow(), globals);
if (!bResult)
goto FAILURE;
break;
case (STATUSDIALOG | HAVESETTINGS | ANSWERCALL):
bResult = DoAnswer(ghInstance, GetForegroundWindow(), globals);
if (!bResult)
goto FAILURE;
break;
case (RETURNSTATUS | NOSETTINGS | DIALCALL):
case (RETURNSTATUS | NOSETTINGS | ANSWERCALL):
DPF(0, "Invalid flags - no phone number or modem specified");
hr = DPERR_INVALIDPARAM;
break;
case (RETURNSTATUS | HAVESETTINGS | DIALCALL):
hr = DoDialStatus(globals);
break;
case (RETURNSTATUS | HAVESETTINGS | ANSWERCALL):
hr = DoAnswerStatus(globals);
break;
}
return (hr);
FAILURE:
DisconnectModem(baseObject);
return (DPERR_USERCANCEL);
}
/*
* DisconnectModem
*
* Hang up any call in progress.
*/
static HRESULT DisconnectModem(LPDPCOMPORT baseObject)
{
LPDPMODEM globals = (LPDPMODEM) baseObject;
LPDPDIAL lpDial = globals->lpDial;
// dial object has not been created?
if (lpDial == NULL)
return (DPERR_INVALIDPARAM);
// disconnect the call
dialDropCall(lpDial);
dialDeallocCall(lpDial);
dialLineClose(lpDial);
return (DP_OK);
}
/*
* GetModemAddress
*
* Return current modem address if available.
*/
static HRESULT GetModemAddress(LPDPCOMPORT baseObject, DWORD dwPlayerFlags,
LPVOID lpAddress, LPDWORD lpdwAddressSize)
{
LPDPMODEM globals = (LPDPMODEM) baseObject;
LPDPDIAL lpDial = globals->lpDial;
WCHAR szPhoneNumberW[PHONENUMBERSIZE];
DPCOMPOUNDADDRESSELEMENT addressElements[3];
HRESULT hr;
// no settings?
if (!globals->bHaveSettings)
return (DPERR_UNAVAILABLE);
// dial object has not been created?
if (lpDial == NULL)
return (DPERR_UNAVAILABLE);
// not connected?
if (!dialIsConnected(lpDial))
return (DPERR_UNAVAILABLE);
// if we answered there is no way for us to know a phone number
if (globals->bAnswering)
return (DPERR_UNAVAILABLE);
// we can't know the phone number of local players, only remote players
if (dwPlayerFlags & DPLAYI_PLAYER_PLAYERLOCAL)
return (DPERR_UNAVAILABLE);
// get UNICODE version of phone number
if (!AnsiToWide(szPhoneNumberW, globals->szPhoneNumber, PHONENUMBERSIZE))
return (DPERR_GENERIC);
// service provider chunk
addressElements[0].guidDataType = DPAID_ServiceProvider;
addressElements[0].dwDataSize = sizeof(GUID);
addressElements[0].lpData = &DPMODEM_GUID;
// ANSI phone number
addressElements[1].guidDataType = DPAID_Phone;
addressElements[1].dwDataSize = lstrlen(globals->szPhoneNumber) + 1;
addressElements[1].lpData = globals->szPhoneNumber;
// UNICODE phone number
addressElements[2].guidDataType = DPAID_PhoneW;
addressElements[2].dwDataSize = (lstrlen(globals->szPhoneNumber) + 1) * sizeof(WCHAR);
addressElements[2].lpData = szPhoneNumberW;
// create the address
hr = baseObject->lpDPlay->lpVtbl->CreateCompoundAddress(baseObject->lpDPlay,
addressElements, 3,
lpAddress, lpdwAddressSize);
return (hr);
}
/*
* GetModemAddressChoices
*
* Return modem address choices
*/
static HRESULT GetModemAddressChoices(LPDPCOMPORT baseObject,
LPVOID lpAddress, LPDWORD lpdwAddressSize)
{
LPDPMODEM globals = (LPDPMODEM) baseObject;
LPDPDIAL lpDial = globals->lpDial;
DPCOMPOUNDADDRESSELEMENT addressElements[3];
LINERESULT lResult;
HRESULT hr;
// dial object has not been created?
if (lpDial == NULL)
return (DPERR_UNAVAILABLE);
ZeroMemory(addressElements, sizeof(addressElements));
// service provider chunk
addressElements[0].guidDataType = DPAID_ServiceProvider;
addressElements[0].dwDataSize = sizeof(GUID);
addressElements[0].lpData = &DPMODEM_GUID;
// get ANSI modem name list
addressElements[1].guidDataType = DPAID_Modem;
lResult = dialGetModemList(lpDial, TRUE,
&addressElements[1].lpData,
&addressElements[1].dwDataSize);
if (lResult)
{
hr = DPERR_OUTOFMEMORY;
goto Failure;
}
// Unicode modem name list
addressElements[2].guidDataType = DPAID_ModemW;
lResult = dialGetModemList(lpDial, FALSE,
&addressElements[2].lpData,
&addressElements[2].dwDataSize);
if (lResult)
{
hr = DPERR_OUTOFMEMORY;
goto Failure;
}
// create the address
hr = baseObject->lpDPlay->lpVtbl->CreateCompoundAddress(baseObject->lpDPlay,
addressElements, 3,
lpAddress, lpdwAddressSize);
Failure:
if (addressElements[1].lpData)
GlobalFreePtr(addressElements[1].lpData);
if (addressElements[2].lpData)
GlobalFreePtr(addressElements[2].lpData);
return (hr);
}
/*
* GetModemBaudRate
*
* Get baud rate of modem connnection.
*/
static HRESULT GetModemBaudRate(LPDPCOMPORT baseObject, LPDWORD lpdwBaudRate)
{
LPDPMODEM globals = (LPDPMODEM) baseObject;
LPDPDIAL lpDial = globals->lpDial;
LINERESULT lResult;
lResult = dialGetBaudRate(lpDial, lpdwBaudRate);
if (lResult == SUCCESS)
return (DP_OK);
else
return (DPERR_UNAVAILABLE);
}
// Local prototypes
INT_PTR CALLBACK DialSetupWndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK AnswerSetupWndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK ModemStatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void ChangeDialingProperties(HWND hWnd, LPDPDIAL lpDial);
void ConfigureModem(HWND hWnd);
void CenterWindow(HWND, HWND);
// ---------------------------------------------------------------------------
// DoDialSetup
// ---------------------------------------------------------------------------
// Description: Gets modem setup information from the user.
// Arguments:
// HINSTANCE [in] Instance handle to load resources from.
// HWND [in] Parent window handle.
// LPDPMODEM [in] modem globals
// Returns:
// BOOL TRUE on success.
BOOL DoDialSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
{
INT_PTR iResult;
iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_DIAL), hWndParent, DialSetupWndProc, (LPARAM) globals);
return (iResult > 0);
}
// ---------------------------------------------------------------------------
// DialSetupWndProc
// ---------------------------------------------------------------------------
// Description: Message callback function for dial setup dialog.
// Arguments:
// HWND [in] Dialog window handle.
// UINT [in] Window message identifier.
// WPARAM [in] Depends on message.
// LPARAM [in] Depends on message.
// Returns:
// BOOL TRUE if message was processed internally.
INT_PTR CALLBACK DialSetupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPDPMODEM globals = (LPDPMODEM) GetWindowLongPtr(hWnd, DWLP_USER);
switch(uMsg)
{
case WM_INITDIALOG:
// modem info pointer passed in lParam
globals = (LPDPMODEM) lParam;
// save the globals with the window
SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)globals);
// Center over the parent window
CenterWindow(hWnd, GetParent(hWnd));
/* gDPlay->lpVtbl->EnumMRUEntries(gDPlay,
MRU_SP_KEY, MRU_NUMBER_KEY,
EnumMRUPhoneNumbers, (LPVOID) hWnd);
*/
if (lstrlen(globals->szPhoneNumber))
SetDlgItemText(hWnd, IDC_NUMBER, globals->szPhoneNumber);
/* else
SendDlgItemMessage(hWnd,
IDC_NUMBER,
CB_SETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
*/
/* SendDlgItemMessage(hWnd,
IDC_NUMBER,
CB_SETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
*/
// initialize the modem selection combo box
dialFillModemComboBox(globals->lpDial, hWnd, IDC_MODEM, globals->dwDeviceID);
// initialize location combo box
// dialFillLocationComboBox(lpModemInfo->lpDial, hWnd, IDC_DIALINGFROM, gModemSettings.dwLocation);
UpdateButtons(hWnd);
// Set focus so Derek won't have a cow
SetFocus(GetDlgItem(hWnd, IDC_NUMBER));
break;
case WM_DESTROY:
// Return failure
EndDialog(hWnd, FALSE);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_NUMBER:
switch (HIWORD(wParam))
{
case EN_CHANGE:
// case CBN_EDITCHANGE:
UpdateButtons(hWnd);
break;
}
break;
/*
case IDC_DIALPROPERTIES:
ChangeDialingProperties(hWnd, lpModemInfo->lpDial);
dialFillLocationComboBox(lpModemInfo->lpDial, hWnd, IDC_DIALINGFROM, gModemSettings.dwLocation);
break;
*/
case IDC_CONFIGUREMODEM:
ConfigureModem(hWnd);
break;
case IDOK:
{
DWORD dwModemSelection;
// Gather dialing info
// Get phone number
GetDlgItemText(hWnd, IDC_NUMBER, globals->szPhoneNumber, PHONENUMBERSIZE);
//
// get current modem selection and then get the assoicated
// TAPI modem ID
//
dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
DDASSERT( dwModemSelection != CB_ERR );
globals->dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETITEMDATA,
(WPARAM) dwModemSelection,
(LPARAM) 0);
DDASSERT( globals->dwDeviceID != CB_ERR );
/* if (lstrlen(gModemSettings.szPhoneNumber))
{
gDPlay->lpVtbl->AddMRUEntry(gDPlay,
MRU_SP_KEY, MRU_NUMBER_KEY,
gModemSettings.szPhoneNumber, lstrlen(gModemSettings.szPhoneNumber),
MAXPHONENUMBERS);
}
*/
// Dial...
if (DoDial(ghInstance, hWnd, globals))
EndDialog(hWnd, TRUE);
break;
}
case IDCANCEL:
// Return failure
EndDialog(hWnd, FALSE);
break;
}
break;
}
// Allow for default processing
return FALSE;
}
// ---------------------------------------------------------------------------
// DoDial
// ---------------------------------------------------------------------------
// Description: Dials the modem
// Arguments:
// HINSTANCE [in] Instance handle to load resources from.
// HWND [in] Parent window handle.
// LPDPMODEM [in] modem globals
// Returns:
// BOOL TRUE on success.
BOOL DoDial(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
{
INT_PTR iResult;
iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_STATUS), hWndParent, ModemStatusWndProc, (LPARAM) globals);
return (iResult > 0);
}
// ---------------------------------------------------------------------------
// DoAnswerSetup
// ---------------------------------------------------------------------------
// Description: Gets modem setup information from the user.
// Arguments:
// HINSTANCE [in] Instance handle to load resources from.
// HWND [in] Parent window handle.
// LPDPMODEM [in] modem globals
// Returns:
// BOOL TRUE on success.
BOOL DoAnswerSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
{
INT_PTR iResult;
iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_ANSWER), hWndParent, AnswerSetupWndProc, (LPARAM) globals);
return (iResult > 0);
}
// ---------------------------------------------------------------------------
// AnswerSetupWndProc
// ---------------------------------------------------------------------------
// Description: Message callback function for modem setup dialog.
// Arguments:
// HWND [in] Dialog window handle.
// UINT [in] Window message identifier.
// WPARAM [in] Depends on message.
// LPARAM [in] Depends on message.
// Returns:
// BOOL TRUE if message was processed internally.
INT_PTR CALLBACK AnswerSetupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPDPMODEM globals = (LPDPMODEM) GetWindowLongPtr(hWnd, DWLP_USER);
switch(uMsg)
{
case WM_INITDIALOG:
// modem info pointer passed in lParam
globals = (LPDPMODEM) lParam;
// save the globals with the window
SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR) globals);
// Center over the parent window
CenterWindow(hWnd, GetParent(hWnd));
// Initialize the modem selection combo box
dialFillModemComboBox(globals->lpDial, hWnd, IDC_MODEM, globals->dwDeviceID);
// Set focus so Derek won't have a cow
SetFocus(GetDlgItem(hWnd, IDC_MODEM));
break;
case WM_DESTROY:
// Return failure
EndDialog(hWnd, FALSE);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_CONFIGUREMODEM:
ConfigureModem(hWnd);
break;
case IDOK:
{
DWORD dwModemSelection;
//
// Get the current selection and then the associated TAPI
// modem ID.
//
dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
globals->dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETITEMDATA,
(WPARAM) dwModemSelection,
(LPARAM) 0);
// Answer...
if (DoAnswer(ghInstance, hWnd, globals))
EndDialog(hWnd, TRUE);
break;
}
case IDCANCEL:
// Return failure
EndDialog(hWnd, FALSE);
break;
}
break;
}
// Allow for default processing
return FALSE;
}
// ---------------------------------------------------------------------------
// DoAnswer
// ---------------------------------------------------------------------------
// Description: Answers the modem
// Arguments:
// HINSTANCE [in] Instance handle to load resources from.
// HWND [in] Parent window handle.
// LPDPMODEM [in] modem globals
// Returns:
// BOOL TRUE on success.
BOOL DoAnswer(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
{
INT_PTR iResult;
iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_STATUS), hWndParent, ModemStatusWndProc, (LPARAM) globals);
return (iResult > 0);
}
// ---------------------------------------------------------------------------
// ModemStatusWndProc
// ---------------------------------------------------------------------------
// Description: Message callback function for dial setup dialog.
// Arguments:
// HWND [in] Dialog window handle.
// UINT [in] Window message identifier.
// WPARAM [in] Depends on message.
// LPARAM [in] Depends on message.
// Returns:
// BOOL TRUE if message was processed internally.
INT_PTR CALLBACK ModemStatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPDPMODEM globals = (LPDPMODEM) GetWindowLongPtr(hWnd, DWLP_USER);
static UINT_PTR uTimer = 0; /* timer identifier */
LINERESULT lResult;
TCHAR szStr[TEMPSTRINGSIZE]; // temp string
TCHAR szTableStr[TEMPSTRINGSIZE]; // temp string
switch(uMsg)
{
case WM_INITDIALOG:
// modem info pointer passed in lParam
globals = (LPDPMODEM) lParam;
// save the globals with the window
SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR) globals);
// Center over the parent window
CenterWindow(hWnd, GetParent(hWnd));
// Set focus so Allen won't have a cow
SetFocus(GetDlgItem(hWnd, IDCANCEL));
// make sure line is closed
if (globals->lpDial->hLine)
dialLineClose(globals->lpDial);
// open a line
lResult = dialLineOpen(globals->lpDial, globals->dwDeviceID);
if (lResult)
{
// line would not open, so show an error
if (LoadString(ghInstance, IDS_COULDNOTOPENLINE, szStr, sizeof(szStr)))
SetDlgItemText(hWnd, IDC_STATUS, szStr);
break;
}
if (globals->bAnswering)
{
// already have settings, so just exit
if (globals->bHaveSettings)
EndDialog(hWnd, TRUE);
// display "please wait" string
if (LoadString(ghInstance, IDS_WAITINGFORCONNECTION, szStr, sizeof(szStr)))
SetDlgItemText(hWnd, IDC_STATUS, szStr);
}
else
{
if (LoadString(ghInstance, IDS_DIALING, szTableStr, sizeof(szTableStr)))
{
wsprintf(szStr, szTableStr, globals->szPhoneNumber);
SetDlgItemText(hWnd, IDC_STATUS, szStr);
}
// dial phone number
lResult = dialMakeCall(globals->lpDial, globals->szPhoneNumber);
if (lResult < 0)
{
// could not dial call, so show an error
if (LoadString(ghInstance, IDS_COULDNOTDIAL, szStr, sizeof(szStr)))
SetDlgItemText(hWnd, IDC_STATUS, szStr);
break;
}
// reset to zero so that we don't get a false no connection below
globals->lpDial->dwCallState = 0;
}
uTimer = SetTimer(hWnd, 1, TIMERINTERVAL, NULL);
break;
case WM_TIMER:
if (dialIsConnected(globals->lpDial))
{
if (uTimer)
{
KillTimer(hWnd, uTimer);
uTimer = 0;
}
// give the other side some time to set up
Sleep(500);
EndDialog(hWnd, TRUE);
}
// see if line has failed
else if (globals->lpDial->dwCallError != CALL_OK)
{
// show an error
if (LoadString(ghInstance,
globals->bAnswering ? IDS_COULDNOTOPENLINE : IDS_COULDNOTDIAL,
szStr, sizeof(szStr)))
SetDlgItemText(hWnd, IDC_STATUS, szStr);
}
break;
case WM_DESTROY:
if (uTimer)
{
KillTimer(hWnd, uTimer);
uTimer = 0;
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
case IDCANCEL:
// disconnect the call
dialDropCall(globals->lpDial);
dialDeallocCall(globals->lpDial);
dialLineClose(globals->lpDial);
// Return failure
EndDialog(hWnd, FALSE);
break;
}
break;
}
// Allow for default processing
return FALSE;
}
HRESULT DoDialStatus(LPDPMODEM globals)
{
LINERESULT lResult;
// see if line had an error or went idle
if ((globals->lpDial->dwCallError != CALL_OK) ||
((globals->lpDial->hLine) &&
(globals->lpDial->dwCallState == LINECALLSTATE_IDLE)))
{
DPF(3, "DoDialStatus error recovery");
// some errors don't close the line so we will
if (globals->lpDial->hLine)
dialLineClose(globals->lpDial);
// reset the error state
globals->lpDial->dwCallError = CALL_OK;
return (DPERR_NOCONNECTION);
}
// line is not open
if (!globals->lpDial->hLine)
{
lResult = dialLineOpen(globals->lpDial, globals->dwDeviceID);
if (lResult)
return (DPERR_NOCONNECTION);
lResult = dialMakeCall(globals->lpDial, globals->szPhoneNumber);
if (lResult < 0)
{
dialLineClose(globals->lpDial);
return (DPERR_NOCONNECTION);
}
// reset to zero so that we don't get a false "no connection" before we dial
globals->lpDial->dwCallState = 0;
}
// if we got here then call is in progress
return (DPERR_CONNECTING);
}
HRESULT DoAnswerStatus(LPDPMODEM globals)
{
LINERESULT lResult;
// see if line had an error
if (globals->lpDial->dwCallError != CALL_OK)
{
// some errors don't close the line so we will
if (globals->lpDial->hLine)
dialLineClose(globals->lpDial);
// reset the error state
globals->lpDial->dwCallError = CALL_OK;
return (DPERR_NOCONNECTION);
}
// open a line
if (!globals->lpDial->hLine)
{
lResult = dialLineOpen(globals->lpDial, globals->dwDeviceID);
if (lResult)
return (DPERR_NOCONNECTION);
}
// if we got here then we are ready to answer a call
return (DP_OK);
}
static BOOL FAR PASCAL EnumMRUPhoneNumbers(LPCVOID lpData, DWORD dwDataSize, LPVOID lpContext)
{
HWND hWnd = (HWND) lpContext;
SendDlgItemMessage(hWnd,
IDC_NUMBER,
CB_ADDSTRING,
(WPARAM) 0,
(LPARAM) lpData);
return (TRUE);
}
static void UpdateButtons(HWND hWnd)
{
LONG_PTR len;
// see how much text has been typed into number edit
len = SendDlgItemMessage(hWnd,
IDC_NUMBER,
WM_GETTEXTLENGTH,
(WPARAM) 0,
(LPARAM) 0);
// only enable "Connect" button if text has been entered
EnableWindow(GetDlgItem(hWnd, IDOK), (len == 0) ? FALSE : TRUE);
}
void ChangeDialingProperties(HWND hWnd, LPDPDIAL lpDial)
{
TCHAR szPhoneNumber[PHONENUMBERSIZE];
DWORD dwModemSelection;
DWORD dwDeviceID;
LINERESULT lResult;
dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
DDASSERT( dwModemSelection != CB_ERR );
dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETITEMDATA,
(WPARAM) dwModemSelection,
(LPARAM) 0);
DDASSERT( dwDeviceID != CB_ERR );
if (dwDeviceID == CB_ERR)
return;
GetDlgItemText(hWnd, IDC_NUMBER, szPhoneNumber, PHONENUMBERSIZE);
lResult = dialTranslateDialog(lpDial, hWnd, dwDeviceID, szPhoneNumber);
}
void ConfigureModem(HWND hWnd)
{
DWORD dwDeviceID;
DWORD dwModemSelection;
LINERESULT lResult;
//
// get the current modem selection and then get the associated TAPI modem ID
//
dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETCURSEL,
(WPARAM) 0,
(LPARAM) 0);
DDASSERT( dwModemSelection != CB_ERR );
dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
IDC_MODEM,
CB_GETITEMDATA,
(WPARAM) dwModemSelection,
(LPARAM) 0);
DDASSERT( dwDeviceID != CB_ERR );
if (dwDeviceID != CB_ERR)
lResult = lineConfigDialog(dwDeviceID, hWnd, "comm/datamodem");
}
// ---------------------------------------------------------------------------
// CenterWidow
// ---------------------------------------------------------------------------
// Description: Centers one window over another.
// Arguments:
// HWND [in] Window handle.
// HWND [in] Parent window handle. NULL centers the
// window over the desktop.
// Returns:
// void
void CenterWindow(HWND hWnd, HWND hWndParent)
{
RECT rcWindow, rcParent;
int x, y;
// Get child window rect
GetWindowRect(hWnd, &rcWindow);
// Get parent window rect
// if(!hWndParent || !IsWindow(hWndParent))
{
hWndParent = GetDesktopWindow();
}
GetWindowRect(hWndParent, &rcParent);
// Calculate XY coordinates
x = ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2;
y = ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2;
// Center the window
SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}