Leaked source code of windows server 2003
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.

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