Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1165 lines
32 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1996-1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: modem.c
  6. * Content: Routines for modem I/O
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 6/10/96 kipo created it
  11. * 6/22/96 kipo added support for EnumConnectionData(); dim "OK" button
  12. * until user types at least one character.
  13. * 6/25/96 kipo updated for DPADDRESS
  14. * 7/08/96 kipo added support for new dialogs
  15. * 7/13/96 kipo added GetModemAddress()
  16. * 7/16/96 kipo changed address types to be GUIDs instead of 4CC
  17. * 8/10/96 kipo added support for dialing location
  18. * 8/15/96 kipo commented out support for dialing location
  19. * 9/04/96 dereks fixed focus in dial/answer dialogs
  20. * 1/06/97 kipo updated for objects
  21. * 2/11/97 kipo pass player flags to GetAddress()
  22. * 2/18/97 kipo allow multiple instances of service provider
  23. * 3/04/97 kipo close com port handle when deallocating call; use string
  24. * table for modem strings; updated debug output.
  25. * 3/17/97 kipo added support for Unicode phone numbers
  26. * 3/24/97 kipo added support for specifying which modem to use
  27. * 4/08/97 kipo added support for separate modem and serial baud rates
  28. * 5/07/97 kipo added support for modem choice list
  29. * 5/23/97 kipo added support return status codes
  30. * 5/25/97 kipo use DPERR_CONNECTING error to return status; set focus
  31. * on cancel button in status window
  32. * 6/03/97 kipo really make the cancel button work with return
  33. * 2/01/98 kipo Display an error string in status dialog if line goes
  34. * idle while dialing. Fixes bug #15251
  35. * 5/08/98 a-peterz #15251 - Better error state detection
  36. * 10/13/99 johnkan #413516 - Mismatch between modem dialog selection and TAPI device ID
  37. ***************************************************************************/
  38. #include <windows.h>
  39. #include <windowsx.h>
  40. #include "dplaysp.h"
  41. #include "dputils.h"
  42. #include "dial.h"
  43. #include "dpf.h"
  44. #include "resource.h"
  45. // constants
  46. enum {
  47. PHONENUMBERSIZE = 200, // size of phone number string
  48. MODEMNAMESIZE = 200, // size of modem name string
  49. TEMPSTRINGSIZE = 300, // size of temporary strings
  50. MODEMTIMEOUT = 30 * 1000, // milliseconds to wait for phone to connect
  51. MODEMSLEEPTIME = 50, // milliseconds to sleep while waiting for modem
  52. TIMERINTERVAL = 100,
  53. MAXPHONENUMBERS = 10
  54. };
  55. // bit masks used to select connection actions
  56. enum {
  57. DIALCALL = (0 << 0), // make a call
  58. ANSWERCALL = (1 << 0), // answer a call
  59. NOSETTINGS = (0 << 1), // no phone settings are set
  60. HAVESETTINGS = (1 << 1), // phone settings are set
  61. STATUSDIALOG = (0 << 2), // show a connection status dialog
  62. RETURNSTATUS = (1 << 2) // return status to app
  63. };
  64. #define MRU_SP_KEY L"Modem Connection For DirectPlay"
  65. #define MRU_NUMBER_KEY L"Phone Number"
  66. // structures
  67. // modem object
  68. typedef struct {
  69. DPCOMPORT comPort; // base object globals
  70. LPDPDIAL lpDial; // dialing globals
  71. BOOL bHaveSettings; // set to TRUE if we have settings
  72. BOOL bAnswering; // set to TRUE if we are answering
  73. DWORD dwDeviceID; // device id to use
  74. DWORD dwLocation; // location to use
  75. TCHAR szPhoneNumber[PHONENUMBERSIZE]; // phone number to use
  76. } DPMODEM, *LPDPMODEM;
  77. // globals
  78. // this is defined in dllmain.c
  79. extern HINSTANCE ghInstance;
  80. // this is defined in dpserial.c
  81. extern GUID DPMODEM_GUID;
  82. // prototypes
  83. static HRESULT DisposeModem(LPDPCOMPORT baseObject);
  84. static HRESULT ConnectModem(LPDPCOMPORT baseObject, BOOL bWaitForConnection, BOOL bReturnStatus);
  85. static HRESULT DisconnectModem(LPDPCOMPORT baseObject);
  86. static HRESULT GetModemBaudRate(LPDPCOMPORT baseObject, LPDWORD lpdwBaudRate);
  87. static HRESULT GetModemAddress(LPDPCOMPORT baseObject, DWORD dwPlayerFlags,
  88. LPVOID lpAddress, LPDWORD lpdwAddressSize);
  89. static BOOL FAR PASCAL EnumAddressData(REFGUID lpguidDataType, DWORD dwDataSize,
  90. LPCVOID lpData, LPVOID lpContext);
  91. static HRESULT GetModemAddressChoices(LPDPCOMPORT baseObject,
  92. LPVOID lpAddress, LPDWORD lpdwAddressSize);
  93. static BOOL FAR PASCAL EnumMRUPhoneNumbers(LPCVOID lpData, DWORD dwDataSize, LPVOID lpContext);
  94. static void UpdateButtons(HWND hWnd);
  95. BOOL DoDialSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
  96. BOOL DoDial(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
  97. BOOL DoAnswerSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
  98. BOOL DoAnswer(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals);
  99. HRESULT DoDialStatus(LPDPMODEM globals);
  100. HRESULT DoAnswerStatus(LPDPMODEM globals);
  101. /*
  102. * NewModem
  103. *
  104. * Create new modem object. Open TAPI and verify there are lines available.
  105. */
  106. HRESULT NewModem(LPVOID lpConnectionData, DWORD dwConnectionDataSize,
  107. LPDIRECTPLAYSP lpDPlay, LPREADROUTINE lpReadRoutine,
  108. LPDPCOMPORT *storage)
  109. {
  110. LPDPCOMPORT baseObject;
  111. LPDPMODEM globals;
  112. LINERESULT lResult;
  113. HRESULT hr;
  114. // create base object with enough space for our globals
  115. hr = NewComPort(sizeof(DPMODEM), lpDPlay, lpReadRoutine, &baseObject);
  116. if FAILED(hr)
  117. return (hr);
  118. // fill in methods we implement
  119. baseObject->Dispose = DisposeModem;
  120. baseObject->Connect = ConnectModem;
  121. baseObject->Disconnect = DisconnectModem;
  122. baseObject->GetBaudRate = GetModemBaudRate;
  123. baseObject->GetAddress = GetModemAddress;
  124. baseObject->GetAddressChoices = GetModemAddressChoices;
  125. globals = (LPDPMODEM) baseObject;
  126. // initialize TAPI
  127. lResult = dialInitialize(ghInstance, TEXT("TapiSP"), (LPDPCOMPORT) globals, &globals->lpDial);
  128. if (lResult)
  129. {
  130. hr = DPERR_UNAVAILABLE;
  131. goto Failure;
  132. }
  133. // check for valid connection data
  134. if (lpConnectionData)
  135. {
  136. baseObject->lpDPlay->lpVtbl->EnumAddress(baseObject->lpDPlay, EnumAddressData,
  137. lpConnectionData, dwConnectionDataSize,
  138. globals);
  139. }
  140. // return object pointer
  141. *storage = baseObject;
  142. return (DP_OK);
  143. Failure:
  144. DisposeModem(baseObject);
  145. return (hr);
  146. }
  147. /*
  148. * EnumConnectionData
  149. *
  150. * Search for valid connection data
  151. */
  152. static BOOL FAR PASCAL EnumAddressData(REFGUID lpguidDataType, DWORD dwDataSize,
  153. LPCVOID lpData, LPVOID lpContext)
  154. {
  155. LPDPMODEM globals = (LPDPMODEM) lpContext;
  156. CHAR szModemName[MODEMNAMESIZE];
  157. // this is an ANSI phone number
  158. if ((IsEqualGUID(lpguidDataType, &DPAID_Phone)) &&
  159. (dwDataSize) )
  160. {
  161. // make sure there is room (for terminating null too)
  162. if (dwDataSize > (PHONENUMBERSIZE - 1))
  163. dwDataSize = (PHONENUMBERSIZE - 1);
  164. CopyMemory(globals->szPhoneNumber, lpData, dwDataSize);
  165. globals->bHaveSettings = TRUE; // we have a phone number
  166. }
  167. // this is an UNICODE phone number
  168. else if ((IsEqualGUID(lpguidDataType, &DPAID_PhoneW)) &&
  169. (dwDataSize) )
  170. {
  171. if (WideToAnsi(globals->szPhoneNumber, (LPWSTR) lpData, PHONENUMBERSIZE))
  172. globals->bHaveSettings = TRUE; // we have a phone number
  173. }
  174. // this is an ANSI modem name
  175. else if ((IsEqualGUID(lpguidDataType, &DPAID_Modem)) &&
  176. (dwDataSize) )
  177. {
  178. // search modem list for this name
  179. if (dialGetDeviceIDFromName(globals->lpDial, lpData, &globals->dwDeviceID) == SUCCESS)
  180. globals->bHaveSettings = TRUE; // can answer the phone
  181. }
  182. // this is a UNICODE modem name
  183. else if ((IsEqualGUID(lpguidDataType, &DPAID_ModemW)) &&
  184. (dwDataSize) )
  185. {
  186. // search modem list for this name
  187. if (WideToAnsi(szModemName, (LPWSTR) lpData, MODEMNAMESIZE))
  188. {
  189. if (dialGetDeviceIDFromName(globals->lpDial, szModemName, &globals->dwDeviceID) == SUCCESS)
  190. globals->bHaveSettings = TRUE; // we have a phone number
  191. }
  192. }
  193. return (TRUE);
  194. }
  195. /*
  196. * DisposeModem
  197. *
  198. * Dispose modem object.
  199. */
  200. static HRESULT DisposeModem(LPDPCOMPORT baseObject)
  201. {
  202. LPDPMODEM globals = (LPDPMODEM) baseObject;
  203. LPDPDIAL lpDial = globals->lpDial;
  204. LINERESULT lResult;
  205. // shut down modem
  206. if (lpDial)
  207. lResult = dialShutdown(lpDial);
  208. // free object
  209. GlobalFreePtr((HGLOBAL) baseObject);
  210. return (DP_OK);
  211. }
  212. /*
  213. * ConnectModem
  214. *
  215. * Dial number based on user settings.
  216. */
  217. static HRESULT ConnectModem(LPDPCOMPORT baseObject,
  218. BOOL bWaitForConnection, BOOL bReturnStatus)
  219. {
  220. LPDPMODEM globals = (LPDPMODEM) baseObject;
  221. LPDPDIAL lpDial = globals->lpDial;
  222. DWORD dwFeatures;
  223. BOOL bResult;
  224. HRESULT hr;
  225. // dial object has not been created?
  226. if (lpDial == NULL)
  227. return (DPERR_INVALIDPARAM);
  228. // are we already connected?
  229. if (dialIsConnected(lpDial))
  230. return (DP_OK);
  231. // remember if we are answering or not
  232. globals->bAnswering = bWaitForConnection;
  233. dwFeatures = 0;
  234. if (globals->bAnswering)
  235. dwFeatures |= ANSWERCALL;
  236. if (globals->bHaveSettings)
  237. dwFeatures |= HAVESETTINGS;
  238. if (bReturnStatus)
  239. dwFeatures |= RETURNSTATUS;
  240. hr = DP_OK;
  241. switch (dwFeatures)
  242. {
  243. case (STATUSDIALOG | NOSETTINGS | DIALCALL):
  244. bResult = DoDialSetup(ghInstance, GetForegroundWindow(), globals);
  245. if (!bResult)
  246. goto FAILURE;
  247. globals->bHaveSettings = TRUE;
  248. break;
  249. case (STATUSDIALOG | NOSETTINGS | ANSWERCALL):
  250. bResult = DoAnswerSetup(ghInstance, GetForegroundWindow(), globals);
  251. if (!bResult)
  252. goto FAILURE;
  253. globals->bHaveSettings = TRUE;
  254. break;
  255. case (STATUSDIALOG | HAVESETTINGS | DIALCALL):
  256. bResult = DoDial(ghInstance, GetForegroundWindow(), globals);
  257. if (!bResult)
  258. goto FAILURE;
  259. break;
  260. case (STATUSDIALOG | HAVESETTINGS | ANSWERCALL):
  261. bResult = DoAnswer(ghInstance, GetForegroundWindow(), globals);
  262. if (!bResult)
  263. goto FAILURE;
  264. break;
  265. case (RETURNSTATUS | NOSETTINGS | DIALCALL):
  266. case (RETURNSTATUS | NOSETTINGS | ANSWERCALL):
  267. DPF(0, "Invalid flags - no phone number or modem specified");
  268. hr = DPERR_INVALIDPARAM;
  269. break;
  270. case (RETURNSTATUS | HAVESETTINGS | DIALCALL):
  271. hr = DoDialStatus(globals);
  272. break;
  273. case (RETURNSTATUS | HAVESETTINGS | ANSWERCALL):
  274. hr = DoAnswerStatus(globals);
  275. break;
  276. }
  277. return (hr);
  278. FAILURE:
  279. DisconnectModem(baseObject);
  280. return (DPERR_USERCANCEL);
  281. }
  282. /*
  283. * DisconnectModem
  284. *
  285. * Hang up any call in progress.
  286. */
  287. static HRESULT DisconnectModem(LPDPCOMPORT baseObject)
  288. {
  289. LPDPMODEM globals = (LPDPMODEM) baseObject;
  290. LPDPDIAL lpDial = globals->lpDial;
  291. // dial object has not been created?
  292. if (lpDial == NULL)
  293. return (DPERR_INVALIDPARAM);
  294. // disconnect the call
  295. dialDropCall(lpDial);
  296. dialDeallocCall(lpDial);
  297. dialLineClose(lpDial);
  298. return (DP_OK);
  299. }
  300. /*
  301. * GetModemAddress
  302. *
  303. * Return current modem address if available.
  304. */
  305. static HRESULT GetModemAddress(LPDPCOMPORT baseObject, DWORD dwPlayerFlags,
  306. LPVOID lpAddress, LPDWORD lpdwAddressSize)
  307. {
  308. LPDPMODEM globals = (LPDPMODEM) baseObject;
  309. LPDPDIAL lpDial = globals->lpDial;
  310. WCHAR szPhoneNumberW[PHONENUMBERSIZE];
  311. DPCOMPOUNDADDRESSELEMENT addressElements[3];
  312. HRESULT hr;
  313. // no settings?
  314. if (!globals->bHaveSettings)
  315. return (DPERR_UNAVAILABLE);
  316. // dial object has not been created?
  317. if (lpDial == NULL)
  318. return (DPERR_UNAVAILABLE);
  319. // not connected?
  320. if (!dialIsConnected(lpDial))
  321. return (DPERR_UNAVAILABLE);
  322. // if we answered there is no way for us to know a phone number
  323. if (globals->bAnswering)
  324. return (DPERR_UNAVAILABLE);
  325. // we can't know the phone number of local players, only remote players
  326. if (dwPlayerFlags & DPLAYI_PLAYER_PLAYERLOCAL)
  327. return (DPERR_UNAVAILABLE);
  328. // get UNICODE version of phone number
  329. if (!AnsiToWide(szPhoneNumberW, globals->szPhoneNumber, PHONENUMBERSIZE))
  330. return (DPERR_GENERIC);
  331. // service provider chunk
  332. addressElements[0].guidDataType = DPAID_ServiceProvider;
  333. addressElements[0].dwDataSize = sizeof(GUID);
  334. addressElements[0].lpData = &DPMODEM_GUID;
  335. // ANSI phone number
  336. addressElements[1].guidDataType = DPAID_Phone;
  337. addressElements[1].dwDataSize = lstrlen(globals->szPhoneNumber) + 1;
  338. addressElements[1].lpData = globals->szPhoneNumber;
  339. // UNICODE phone number
  340. addressElements[2].guidDataType = DPAID_PhoneW;
  341. addressElements[2].dwDataSize = (lstrlen(globals->szPhoneNumber) + 1) * sizeof(WCHAR);
  342. addressElements[2].lpData = szPhoneNumberW;
  343. // create the address
  344. hr = baseObject->lpDPlay->lpVtbl->CreateCompoundAddress(baseObject->lpDPlay,
  345. addressElements, 3,
  346. lpAddress, lpdwAddressSize);
  347. return (hr);
  348. }
  349. /*
  350. * GetModemAddressChoices
  351. *
  352. * Return modem address choices
  353. */
  354. static HRESULT GetModemAddressChoices(LPDPCOMPORT baseObject,
  355. LPVOID lpAddress, LPDWORD lpdwAddressSize)
  356. {
  357. LPDPMODEM globals = (LPDPMODEM) baseObject;
  358. LPDPDIAL lpDial = globals->lpDial;
  359. DPCOMPOUNDADDRESSELEMENT addressElements[3];
  360. LINERESULT lResult;
  361. HRESULT hr;
  362. // dial object has not been created?
  363. if (lpDial == NULL)
  364. return (DPERR_UNAVAILABLE);
  365. ZeroMemory(addressElements, sizeof(addressElements));
  366. // service provider chunk
  367. addressElements[0].guidDataType = DPAID_ServiceProvider;
  368. addressElements[0].dwDataSize = sizeof(GUID);
  369. addressElements[0].lpData = &DPMODEM_GUID;
  370. // get ANSI modem name list
  371. addressElements[1].guidDataType = DPAID_Modem;
  372. lResult = dialGetModemList(lpDial, TRUE,
  373. &addressElements[1].lpData,
  374. &addressElements[1].dwDataSize);
  375. if (lResult)
  376. {
  377. hr = DPERR_OUTOFMEMORY;
  378. goto Failure;
  379. }
  380. // Unicode modem name list
  381. addressElements[2].guidDataType = DPAID_ModemW;
  382. lResult = dialGetModemList(lpDial, FALSE,
  383. &addressElements[2].lpData,
  384. &addressElements[2].dwDataSize);
  385. if (lResult)
  386. {
  387. hr = DPERR_OUTOFMEMORY;
  388. goto Failure;
  389. }
  390. // create the address
  391. hr = baseObject->lpDPlay->lpVtbl->CreateCompoundAddress(baseObject->lpDPlay,
  392. addressElements, 3,
  393. lpAddress, lpdwAddressSize);
  394. Failure:
  395. if (addressElements[1].lpData)
  396. GlobalFreePtr(addressElements[1].lpData);
  397. if (addressElements[2].lpData)
  398. GlobalFreePtr(addressElements[2].lpData);
  399. return (hr);
  400. }
  401. /*
  402. * GetModemBaudRate
  403. *
  404. * Get baud rate of modem connnection.
  405. */
  406. static HRESULT GetModemBaudRate(LPDPCOMPORT baseObject, LPDWORD lpdwBaudRate)
  407. {
  408. LPDPMODEM globals = (LPDPMODEM) baseObject;
  409. LPDPDIAL lpDial = globals->lpDial;
  410. LINERESULT lResult;
  411. lResult = dialGetBaudRate(lpDial, lpdwBaudRate);
  412. if (lResult == SUCCESS)
  413. return (DP_OK);
  414. else
  415. return (DPERR_UNAVAILABLE);
  416. }
  417. // Local prototypes
  418. INT_PTR CALLBACK DialSetupWndProc(HWND, UINT, WPARAM, LPARAM);
  419. INT_PTR CALLBACK AnswerSetupWndProc(HWND, UINT, WPARAM, LPARAM);
  420. INT_PTR CALLBACK ModemStatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  421. void ChangeDialingProperties(HWND hWnd, LPDPDIAL lpDial);
  422. void ConfigureModem(HWND hWnd);
  423. void CenterWindow(HWND, HWND);
  424. // ---------------------------------------------------------------------------
  425. // DoDialSetup
  426. // ---------------------------------------------------------------------------
  427. // Description: Gets modem setup information from the user.
  428. // Arguments:
  429. // HINSTANCE [in] Instance handle to load resources from.
  430. // HWND [in] Parent window handle.
  431. // LPDPMODEM [in] modem globals
  432. // Returns:
  433. // BOOL TRUE on success.
  434. BOOL DoDialSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
  435. {
  436. INT_PTR iResult;
  437. iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_DIAL), hWndParent, DialSetupWndProc, (LPARAM) globals);
  438. return (iResult > 0);
  439. }
  440. // ---------------------------------------------------------------------------
  441. // DialSetupWndProc
  442. // ---------------------------------------------------------------------------
  443. // Description: Message callback function for dial setup dialog.
  444. // Arguments:
  445. // HWND [in] Dialog window handle.
  446. // UINT [in] Window message identifier.
  447. // WPARAM [in] Depends on message.
  448. // LPARAM [in] Depends on message.
  449. // Returns:
  450. // BOOL TRUE if message was processed internally.
  451. INT_PTR CALLBACK DialSetupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  452. {
  453. LPDPMODEM globals = (LPDPMODEM) GetWindowLongPtr(hWnd, DWLP_USER);
  454. switch(uMsg)
  455. {
  456. case WM_INITDIALOG:
  457. // modem info pointer passed in lParam
  458. globals = (LPDPMODEM) lParam;
  459. // save the globals with the window
  460. SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)globals);
  461. // Center over the parent window
  462. CenterWindow(hWnd, GetParent(hWnd));
  463. /* gDPlay->lpVtbl->EnumMRUEntries(gDPlay,
  464. MRU_SP_KEY, MRU_NUMBER_KEY,
  465. EnumMRUPhoneNumbers, (LPVOID) hWnd);
  466. */
  467. if (lstrlen(globals->szPhoneNumber))
  468. SetDlgItemText(hWnd, IDC_NUMBER, globals->szPhoneNumber);
  469. /* else
  470. SendDlgItemMessage(hWnd,
  471. IDC_NUMBER,
  472. CB_SETCURSEL,
  473. (WPARAM) 0,
  474. (LPARAM) 0);
  475. */
  476. /* SendDlgItemMessage(hWnd,
  477. IDC_NUMBER,
  478. CB_SETCURSEL,
  479. (WPARAM) 0,
  480. (LPARAM) 0);
  481. */
  482. // initialize the modem selection combo box
  483. dialFillModemComboBox(globals->lpDial, hWnd, IDC_MODEM, globals->dwDeviceID);
  484. // initialize location combo box
  485. // dialFillLocationComboBox(lpModemInfo->lpDial, hWnd, IDC_DIALINGFROM, gModemSettings.dwLocation);
  486. UpdateButtons(hWnd);
  487. // Set focus so Derek won't have a cow
  488. SetFocus(GetDlgItem(hWnd, IDC_NUMBER));
  489. break;
  490. case WM_DESTROY:
  491. // Return failure
  492. EndDialog(hWnd, FALSE);
  493. break;
  494. case WM_COMMAND:
  495. switch(LOWORD(wParam))
  496. {
  497. case IDC_NUMBER:
  498. switch (HIWORD(wParam))
  499. {
  500. case EN_CHANGE:
  501. // case CBN_EDITCHANGE:
  502. UpdateButtons(hWnd);
  503. break;
  504. }
  505. break;
  506. /*
  507. case IDC_DIALPROPERTIES:
  508. ChangeDialingProperties(hWnd, lpModemInfo->lpDial);
  509. dialFillLocationComboBox(lpModemInfo->lpDial, hWnd, IDC_DIALINGFROM, gModemSettings.dwLocation);
  510. break;
  511. */
  512. case IDC_CONFIGUREMODEM:
  513. ConfigureModem(hWnd);
  514. break;
  515. case IDOK:
  516. {
  517. DWORD dwModemSelection;
  518. // Gather dialing info
  519. // Get phone number
  520. GetDlgItemText(hWnd, IDC_NUMBER, globals->szPhoneNumber, PHONENUMBERSIZE);
  521. //
  522. // get current modem selection and then get the assoicated
  523. // TAPI modem ID
  524. //
  525. dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
  526. IDC_MODEM,
  527. CB_GETCURSEL,
  528. (WPARAM) 0,
  529. (LPARAM) 0);
  530. DDASSERT( dwModemSelection != CB_ERR );
  531. globals->dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
  532. IDC_MODEM,
  533. CB_GETITEMDATA,
  534. (WPARAM) dwModemSelection,
  535. (LPARAM) 0);
  536. DDASSERT( globals->dwDeviceID != CB_ERR );
  537. /* if (lstrlen(gModemSettings.szPhoneNumber))
  538. {
  539. gDPlay->lpVtbl->AddMRUEntry(gDPlay,
  540. MRU_SP_KEY, MRU_NUMBER_KEY,
  541. gModemSettings.szPhoneNumber, lstrlen(gModemSettings.szPhoneNumber),
  542. MAXPHONENUMBERS);
  543. }
  544. */
  545. // Dial...
  546. if (DoDial(ghInstance, hWnd, globals))
  547. EndDialog(hWnd, TRUE);
  548. break;
  549. }
  550. case IDCANCEL:
  551. // Return failure
  552. EndDialog(hWnd, FALSE);
  553. break;
  554. }
  555. break;
  556. }
  557. // Allow for default processing
  558. return FALSE;
  559. }
  560. // ---------------------------------------------------------------------------
  561. // DoDial
  562. // ---------------------------------------------------------------------------
  563. // Description: Dials the modem
  564. // Arguments:
  565. // HINSTANCE [in] Instance handle to load resources from.
  566. // HWND [in] Parent window handle.
  567. // LPDPMODEM [in] modem globals
  568. // Returns:
  569. // BOOL TRUE on success.
  570. BOOL DoDial(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
  571. {
  572. INT_PTR iResult;
  573. iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_STATUS), hWndParent, ModemStatusWndProc, (LPARAM) globals);
  574. return (iResult > 0);
  575. }
  576. // ---------------------------------------------------------------------------
  577. // DoAnswerSetup
  578. // ---------------------------------------------------------------------------
  579. // Description: Gets modem setup information from the user.
  580. // Arguments:
  581. // HINSTANCE [in] Instance handle to load resources from.
  582. // HWND [in] Parent window handle.
  583. // LPDPMODEM [in] modem globals
  584. // Returns:
  585. // BOOL TRUE on success.
  586. BOOL DoAnswerSetup(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
  587. {
  588. INT_PTR iResult;
  589. iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_ANSWER), hWndParent, AnswerSetupWndProc, (LPARAM) globals);
  590. return (iResult > 0);
  591. }
  592. // ---------------------------------------------------------------------------
  593. // AnswerSetupWndProc
  594. // ---------------------------------------------------------------------------
  595. // Description: Message callback function for modem setup dialog.
  596. // Arguments:
  597. // HWND [in] Dialog window handle.
  598. // UINT [in] Window message identifier.
  599. // WPARAM [in] Depends on message.
  600. // LPARAM [in] Depends on message.
  601. // Returns:
  602. // BOOL TRUE if message was processed internally.
  603. INT_PTR CALLBACK AnswerSetupWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  604. {
  605. LPDPMODEM globals = (LPDPMODEM) GetWindowLongPtr(hWnd, DWLP_USER);
  606. switch(uMsg)
  607. {
  608. case WM_INITDIALOG:
  609. // modem info pointer passed in lParam
  610. globals = (LPDPMODEM) lParam;
  611. // save the globals with the window
  612. SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR) globals);
  613. // Center over the parent window
  614. CenterWindow(hWnd, GetParent(hWnd));
  615. // Initialize the modem selection combo box
  616. dialFillModemComboBox(globals->lpDial, hWnd, IDC_MODEM, globals->dwDeviceID);
  617. // Set focus so Derek won't have a cow
  618. SetFocus(GetDlgItem(hWnd, IDC_MODEM));
  619. break;
  620. case WM_DESTROY:
  621. // Return failure
  622. EndDialog(hWnd, FALSE);
  623. break;
  624. case WM_COMMAND:
  625. switch(LOWORD(wParam))
  626. {
  627. case IDC_CONFIGUREMODEM:
  628. ConfigureModem(hWnd);
  629. break;
  630. case IDOK:
  631. {
  632. DWORD dwModemSelection;
  633. //
  634. // Get the current selection and then the associated TAPI
  635. // modem ID.
  636. //
  637. dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
  638. IDC_MODEM,
  639. CB_GETCURSEL,
  640. (WPARAM) 0,
  641. (LPARAM) 0);
  642. globals->dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
  643. IDC_MODEM,
  644. CB_GETITEMDATA,
  645. (WPARAM) dwModemSelection,
  646. (LPARAM) 0);
  647. // Answer...
  648. if (DoAnswer(ghInstance, hWnd, globals))
  649. EndDialog(hWnd, TRUE);
  650. break;
  651. }
  652. case IDCANCEL:
  653. // Return failure
  654. EndDialog(hWnd, FALSE);
  655. break;
  656. }
  657. break;
  658. }
  659. // Allow for default processing
  660. return FALSE;
  661. }
  662. // ---------------------------------------------------------------------------
  663. // DoAnswer
  664. // ---------------------------------------------------------------------------
  665. // Description: Answers the modem
  666. // Arguments:
  667. // HINSTANCE [in] Instance handle to load resources from.
  668. // HWND [in] Parent window handle.
  669. // LPDPMODEM [in] modem globals
  670. // Returns:
  671. // BOOL TRUE on success.
  672. BOOL DoAnswer(HINSTANCE hInstance, HWND hWndParent, LPDPMODEM globals)
  673. {
  674. INT_PTR iResult;
  675. iResult = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MODEM_STATUS), hWndParent, ModemStatusWndProc, (LPARAM) globals);
  676. return (iResult > 0);
  677. }
  678. // ---------------------------------------------------------------------------
  679. // ModemStatusWndProc
  680. // ---------------------------------------------------------------------------
  681. // Description: Message callback function for dial setup dialog.
  682. // Arguments:
  683. // HWND [in] Dialog window handle.
  684. // UINT [in] Window message identifier.
  685. // WPARAM [in] Depends on message.
  686. // LPARAM [in] Depends on message.
  687. // Returns:
  688. // BOOL TRUE if message was processed internally.
  689. INT_PTR CALLBACK ModemStatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  690. {
  691. LPDPMODEM globals = (LPDPMODEM) GetWindowLongPtr(hWnd, DWLP_USER);
  692. static UINT_PTR uTimer = 0; /* timer identifier */
  693. LINERESULT lResult;
  694. TCHAR szStr[TEMPSTRINGSIZE]; // temp string
  695. TCHAR szTableStr[TEMPSTRINGSIZE]; // temp string
  696. switch(uMsg)
  697. {
  698. case WM_INITDIALOG:
  699. // modem info pointer passed in lParam
  700. globals = (LPDPMODEM) lParam;
  701. // save the globals with the window
  702. SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR) globals);
  703. // Center over the parent window
  704. CenterWindow(hWnd, GetParent(hWnd));
  705. // Set focus so Allen won't have a cow
  706. SetFocus(GetDlgItem(hWnd, IDCANCEL));
  707. // make sure line is closed
  708. if (globals->lpDial->hLine)
  709. dialLineClose(globals->lpDial);
  710. // open a line
  711. lResult = dialLineOpen(globals->lpDial, globals->dwDeviceID);
  712. if (lResult)
  713. {
  714. // line would not open, so show an error
  715. if (LoadString(ghInstance, IDS_COULDNOTOPENLINE, szStr, sizeof(szStr)))
  716. SetDlgItemText(hWnd, IDC_STATUS, szStr);
  717. break;
  718. }
  719. if (globals->bAnswering)
  720. {
  721. // already have settings, so just exit
  722. if (globals->bHaveSettings)
  723. EndDialog(hWnd, TRUE);
  724. // display "please wait" string
  725. if (LoadString(ghInstance, IDS_WAITINGFORCONNECTION, szStr, sizeof(szStr)))
  726. SetDlgItemText(hWnd, IDC_STATUS, szStr);
  727. }
  728. else
  729. {
  730. if (LoadString(ghInstance, IDS_DIALING, szTableStr, sizeof(szTableStr)))
  731. {
  732. wsprintf(szStr, szTableStr, globals->szPhoneNumber);
  733. SetDlgItemText(hWnd, IDC_STATUS, szStr);
  734. }
  735. // dial phone number
  736. lResult = dialMakeCall(globals->lpDial, globals->szPhoneNumber);
  737. if (lResult < 0)
  738. {
  739. // could not dial call, so show an error
  740. if (LoadString(ghInstance, IDS_COULDNOTDIAL, szStr, sizeof(szStr)))
  741. SetDlgItemText(hWnd, IDC_STATUS, szStr);
  742. break;
  743. }
  744. // reset to zero so that we don't get a false no connection below
  745. globals->lpDial->dwCallState = 0;
  746. }
  747. uTimer = SetTimer(hWnd, 1, TIMERINTERVAL, NULL);
  748. break;
  749. case WM_TIMER:
  750. if (dialIsConnected(globals->lpDial))
  751. {
  752. if (uTimer)
  753. {
  754. KillTimer(hWnd, uTimer);
  755. uTimer = 0;
  756. }
  757. // give the other side some time to set up
  758. Sleep(500);
  759. EndDialog(hWnd, TRUE);
  760. }
  761. // see if line has failed
  762. else if (globals->lpDial->dwCallError != CALL_OK)
  763. {
  764. // show an error
  765. if (LoadString(ghInstance,
  766. globals->bAnswering ? IDS_COULDNOTOPENLINE : IDS_COULDNOTDIAL,
  767. szStr, sizeof(szStr)))
  768. SetDlgItemText(hWnd, IDC_STATUS, szStr);
  769. }
  770. break;
  771. case WM_DESTROY:
  772. if (uTimer)
  773. {
  774. KillTimer(hWnd, uTimer);
  775. uTimer = 0;
  776. }
  777. break;
  778. case WM_COMMAND:
  779. switch(LOWORD(wParam))
  780. {
  781. case IDOK:
  782. case IDCANCEL:
  783. // disconnect the call
  784. dialDropCall(globals->lpDial);
  785. dialDeallocCall(globals->lpDial);
  786. dialLineClose(globals->lpDial);
  787. // Return failure
  788. EndDialog(hWnd, FALSE);
  789. break;
  790. }
  791. break;
  792. }
  793. // Allow for default processing
  794. return FALSE;
  795. }
  796. HRESULT DoDialStatus(LPDPMODEM globals)
  797. {
  798. LINERESULT lResult;
  799. // see if line had an error or went idle
  800. if ((globals->lpDial->dwCallError != CALL_OK) ||
  801. ((globals->lpDial->hLine) &&
  802. (globals->lpDial->dwCallState == LINECALLSTATE_IDLE)))
  803. {
  804. DPF(3, "DoDialStatus error recovery");
  805. // some errors don't close the line so we will
  806. if (globals->lpDial->hLine)
  807. dialLineClose(globals->lpDial);
  808. // reset the error state
  809. globals->lpDial->dwCallError = CALL_OK;
  810. return (DPERR_NOCONNECTION);
  811. }
  812. // line is not open
  813. if (!globals->lpDial->hLine)
  814. {
  815. lResult = dialLineOpen(globals->lpDial, globals->dwDeviceID);
  816. if (lResult)
  817. return (DPERR_NOCONNECTION);
  818. lResult = dialMakeCall(globals->lpDial, globals->szPhoneNumber);
  819. if (lResult < 0)
  820. {
  821. dialLineClose(globals->lpDial);
  822. return (DPERR_NOCONNECTION);
  823. }
  824. // reset to zero so that we don't get a false "no connection" before we dial
  825. globals->lpDial->dwCallState = 0;
  826. }
  827. // if we got here then call is in progress
  828. return (DPERR_CONNECTING);
  829. }
  830. HRESULT DoAnswerStatus(LPDPMODEM globals)
  831. {
  832. LINERESULT lResult;
  833. // see if line had an error
  834. if (globals->lpDial->dwCallError != CALL_OK)
  835. {
  836. // some errors don't close the line so we will
  837. if (globals->lpDial->hLine)
  838. dialLineClose(globals->lpDial);
  839. // reset the error state
  840. globals->lpDial->dwCallError = CALL_OK;
  841. return (DPERR_NOCONNECTION);
  842. }
  843. // open a line
  844. if (!globals->lpDial->hLine)
  845. {
  846. lResult = dialLineOpen(globals->lpDial, globals->dwDeviceID);
  847. if (lResult)
  848. return (DPERR_NOCONNECTION);
  849. }
  850. // if we got here then we are ready to answer a call
  851. return (DP_OK);
  852. }
  853. static BOOL FAR PASCAL EnumMRUPhoneNumbers(LPCVOID lpData, DWORD dwDataSize, LPVOID lpContext)
  854. {
  855. HWND hWnd = (HWND) lpContext;
  856. SendDlgItemMessage(hWnd,
  857. IDC_NUMBER,
  858. CB_ADDSTRING,
  859. (WPARAM) 0,
  860. (LPARAM) lpData);
  861. return (TRUE);
  862. }
  863. static void UpdateButtons(HWND hWnd)
  864. {
  865. LONG_PTR len;
  866. // see how much text has been typed into number edit
  867. len = SendDlgItemMessage(hWnd,
  868. IDC_NUMBER,
  869. WM_GETTEXTLENGTH,
  870. (WPARAM) 0,
  871. (LPARAM) 0);
  872. // only enable "Connect" button if text has been entered
  873. EnableWindow(GetDlgItem(hWnd, IDOK), (len == 0) ? FALSE : TRUE);
  874. }
  875. void ChangeDialingProperties(HWND hWnd, LPDPDIAL lpDial)
  876. {
  877. TCHAR szPhoneNumber[PHONENUMBERSIZE];
  878. DWORD dwModemSelection;
  879. DWORD dwDeviceID;
  880. LINERESULT lResult;
  881. dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
  882. IDC_MODEM,
  883. CB_GETCURSEL,
  884. (WPARAM) 0,
  885. (LPARAM) 0);
  886. DDASSERT( dwModemSelection != CB_ERR );
  887. dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
  888. IDC_MODEM,
  889. CB_GETITEMDATA,
  890. (WPARAM) dwModemSelection,
  891. (LPARAM) 0);
  892. DDASSERT( dwDeviceID != CB_ERR );
  893. if (dwDeviceID == CB_ERR)
  894. return;
  895. GetDlgItemText(hWnd, IDC_NUMBER, szPhoneNumber, PHONENUMBERSIZE);
  896. lResult = dialTranslateDialog(lpDial, hWnd, dwDeviceID, szPhoneNumber);
  897. }
  898. void ConfigureModem(HWND hWnd)
  899. {
  900. DWORD dwDeviceID;
  901. DWORD dwModemSelection;
  902. LINERESULT lResult;
  903. //
  904. // get the current modem selection and then get the associated TAPI modem ID
  905. //
  906. dwModemSelection = (DWORD)SendDlgItemMessage(hWnd,
  907. IDC_MODEM,
  908. CB_GETCURSEL,
  909. (WPARAM) 0,
  910. (LPARAM) 0);
  911. DDASSERT( dwModemSelection != CB_ERR );
  912. dwDeviceID = (DWORD)SendDlgItemMessage(hWnd,
  913. IDC_MODEM,
  914. CB_GETITEMDATA,
  915. (WPARAM) dwModemSelection,
  916. (LPARAM) 0);
  917. DDASSERT( dwDeviceID != CB_ERR );
  918. if (dwDeviceID != CB_ERR)
  919. lResult = lineConfigDialog(dwDeviceID, hWnd, "comm/datamodem");
  920. }
  921. // ---------------------------------------------------------------------------
  922. // CenterWidow
  923. // ---------------------------------------------------------------------------
  924. // Description: Centers one window over another.
  925. // Arguments:
  926. // HWND [in] Window handle.
  927. // HWND [in] Parent window handle. NULL centers the
  928. // window over the desktop.
  929. // Returns:
  930. // void
  931. void CenterWindow(HWND hWnd, HWND hWndParent)
  932. {
  933. RECT rcWindow, rcParent;
  934. int x, y;
  935. // Get child window rect
  936. GetWindowRect(hWnd, &rcWindow);
  937. // Get parent window rect
  938. // if(!hWndParent || !IsWindow(hWndParent))
  939. {
  940. hWndParent = GetDesktopWindow();
  941. }
  942. GetWindowRect(hWndParent, &rcParent);
  943. // Calculate XY coordinates
  944. x = ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2;
  945. y = ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2;
  946. // Center the window
  947. SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  948. }