/*========================================================================== * * 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 #include #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); }