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.

2656 lines
58 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name:
  4. atsp.c
  5. Notes:
  6. --*/
  7. #include "atsp.h"
  8. BOOL
  9. WINAPI
  10. DllMain(
  11. HANDLE hDLL,
  12. DWORD dwReason,
  13. LPVOID lpReserved
  14. )
  15. {
  16. if (dwReason == DLL_PROCESS_ATTACH)
  17. {
  18. ghInst = hDLL;
  19. #if DBG
  20. {
  21. HKEY hKey;
  22. DWORD dwDataSize, dwDataType;
  23. char szAtsp32DebugLevel[] = "Atsp32DebugLevel";
  24. RegOpenKeyExA(
  25. HKEY_LOCAL_MACHINE,
  26. gszAtspKey,
  27. 0,
  28. KEY_ALL_ACCESS,
  29. &hKey
  30. );
  31. dwDataSize = sizeof (DWORD);
  32. gdwDebugLevel=0;
  33. RegQueryValueEx(
  34. hKey,
  35. szAtsp32DebugLevel,
  36. 0,
  37. &dwDataType,
  38. (LPBYTE) &gdwDebugLevel,
  39. &dwDataSize
  40. );
  41. RegCloseKey (hKey);
  42. }
  43. #endif
  44. }
  45. return TRUE;
  46. }
  47. void
  48. CommThread(
  49. PDRVLINE pLine
  50. )
  51. {
  52. char buf[4];
  53. DWORD dwThreadID = GetCurrentThreadId(), dwNumBytes;
  54. HANDLE hComm = pLine->hComm, hEvent;
  55. LPOVERLAPPED pOverlapped = &pLine->Overlapped;
  56. DBGOUT((
  57. 3,
  58. "CommThread (id=%d): enter, port=%s",
  59. dwThreadID,
  60. pLine->szComm
  61. ));
  62. hEvent = pOverlapped->hEvent;
  63. buf[0] = buf[1] = '.';
  64. //
  65. // Loop waiting for i/o to complete (either the Write done in
  66. // TSPI_lineMakeCall or the Reads done to retrieve status info).
  67. // Note that TSPI_lineDrop or TSPI_lineCloseCall may set the
  68. // event to alert us that they're tearing down the call, in
  69. // which case we just exit.
  70. //
  71. for (;;)
  72. {
  73. if (WaitForSingleObject (hEvent, ATSP_TIMEOUT) == WAIT_OBJECT_0)
  74. {
  75. if (pLine->bDropInProgress == TRUE)
  76. {
  77. DBGOUT((2, "CommThread (id=%d): drop in progress"));
  78. goto CommThread_exit;
  79. }
  80. GetOverlappedResult (hComm, pOverlapped, &dwNumBytes, FALSE);
  81. ResetEvent (hEvent);
  82. }
  83. else
  84. {
  85. DBGOUT((2, "CommThread (id=%d): wait timeout"));
  86. SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  87. goto CommThread_exit;
  88. }
  89. buf[1] &= 0x7f; // nuke the parity bit
  90. DBGOUT((
  91. 3,
  92. "CommThread (id=%d): read '%c'",
  93. dwThreadID,
  94. (buf[1] == '\r' ? '.' : buf[1])
  95. ));
  96. switch ((buf[0] << 8) + buf[1])
  97. {
  98. case 'CT': // "CONNECT"
  99. case 'OK': // "OK"
  100. SetCallState (pLine, LINECALLSTATE_CONNECTED, 0);
  101. goto CommThread_exit;
  102. case 'SY': // "BUSY"
  103. case 'OR': // "ERROR"
  104. case 'NO': // "NO ANSWER", "NO DIALTONE", "NO CARRIER"
  105. SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  106. goto CommThread_exit;
  107. default:
  108. break;
  109. }
  110. buf[0] = buf[1];
  111. ZeroMemory (pOverlapped, sizeof (OVERLAPPED) - sizeof (HANDLE));
  112. if ( 0 == ReadFile (hComm, &buf[1], 1, &dwNumBytes, pOverlapped))
  113. {
  114. DBGOUT((2, "CommThread (id=%d): fail to read from line"));
  115. goto CommThread_exit;
  116. }
  117. }
  118. CommThread_exit:
  119. CloseHandle (hEvent);
  120. DBGOUT((3, "CommThread (id=%d): exit", dwThreadID));
  121. ExitThread (0);
  122. }
  123. //
  124. // We get a slough of C4047 (different levels of indrection) warnings down
  125. // below in the initialization of FUNC_PARAM structs as a result of the
  126. // real func prototypes having params that are types other than DWORDs,
  127. // so since these are known non-interesting warnings just turn them off
  128. //
  129. #pragma warning (disable:4047)
  130. //
  131. // --------------------------- TAPI_lineXxx funcs -----------------------------
  132. //
  133. LONG
  134. TSPIAPI
  135. TSPI_lineClose(
  136. HDRVLINE hdLine
  137. )
  138. {
  139. LONG lResult = 0;
  140. #if DBG
  141. FUNC_PARAM params[] =
  142. {
  143. { gszhdLine, hdLine }
  144. };
  145. FUNC_INFO info =
  146. {
  147. "TSPI_lineClose",
  148. 1,
  149. params,
  150. };
  151. #endif
  152. Prolog (&info);
  153. DrvFree ((PDRVLINE) hdLine);
  154. return (Epilog (&info, lResult));
  155. }
  156. LONG
  157. TSPIAPI
  158. TSPI_lineCloseCall(
  159. HDRVCALL hdCall
  160. )
  161. {
  162. PDRVLINE pLine = (PDRVLINE) hdCall;
  163. #if DBG
  164. FUNC_PARAM params[] =
  165. {
  166. { gszhdCall, hdCall }
  167. };
  168. FUNC_INFO info =
  169. {
  170. "TSPI_lineCloseCall",
  171. 1,
  172. params
  173. };
  174. #endif
  175. //
  176. // Note that in TAPI 2.0 TSPI_lineCloseCall can get called
  177. // without TSPI_lineDrop ever being called, so we need to
  178. // be prepared for either case.
  179. //
  180. Prolog (&info);
  181. DropActiveCall (pLine);
  182. pLine->htCall = NULL;
  183. return (Epilog (&info, 0));
  184. }
  185. LONG
  186. TSPIAPI
  187. TSPI_lineConditionalMediaDetection(
  188. HDRVLINE hdLine,
  189. DWORD dwMediaModes,
  190. LPLINECALLPARAMS const lpCallParams
  191. )
  192. {
  193. #if DBG
  194. FUNC_PARAM params[] =
  195. {
  196. { gszhdLine, hdLine },
  197. { "dwMediaModes", dwMediaModes },
  198. { gszlpCallParams, lpCallParams }
  199. };
  200. FUNC_INFO info =
  201. {
  202. "TSPI_lineConditionalMediaDetection",
  203. 3,
  204. params
  205. };
  206. #endif
  207. //
  208. // This func is really a no-op for us, since we don't look
  209. // for incoming calls (though we do say we support them to
  210. // make apps happy)
  211. //
  212. Prolog (&info);
  213. return (Epilog (&info, 0));
  214. }
  215. LONG
  216. TSPIAPI
  217. TSPI_lineDrop(
  218. DRV_REQUESTID dwRequestID,
  219. HDRVCALL hdCall,
  220. LPCSTR lpsUserUserInfo,
  221. DWORD dwSize
  222. )
  223. {
  224. PDRVLINE pLine = (PDRVLINE) hdCall;
  225. #if DBG
  226. FUNC_PARAM params[] =
  227. {
  228. { gszdwRequestID, dwRequestID },
  229. { gszhdCall, hdCall },
  230. { "lpsUserUserInfo", lpsUserUserInfo },
  231. { gszdwSize, dwSize }
  232. };
  233. FUNC_INFO info =
  234. {
  235. "TSPI_lineDrop",
  236. 4,
  237. params
  238. };
  239. #endif
  240. Prolog (&info);
  241. DropActiveCall (pLine);
  242. SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  243. (*gpfnCompletionProc)(dwRequestID, 0);
  244. return (Epilog (&info, dwRequestID));
  245. }
  246. LONG
  247. TSPIAPI
  248. TSPI_lineGetAddressCaps(
  249. DWORD dwDeviceID,
  250. DWORD dwAddressID,
  251. DWORD dwTSPIVersion,
  252. DWORD dwExtVersion,
  253. LPLINEADDRESSCAPS lpAddressCaps
  254. )
  255. {
  256. #if DBG
  257. FUNC_PARAM params[] =
  258. {
  259. { gszdwDeviceID, dwDeviceID },
  260. { "dwAddressID", dwAddressID },
  261. { "dwTSPIVersion", dwTSPIVersion },
  262. { "dwExtVersion", dwExtVersion },
  263. { "lpAddressCaps", lpAddressCaps }
  264. };
  265. FUNC_INFO info =
  266. {
  267. "TSPI_lineGetAddressCaps",
  268. 5,
  269. params
  270. };
  271. #endif
  272. LONG lResult = 0;
  273. Prolog (&info);
  274. if (dwAddressID != 0)
  275. {
  276. lResult = LINEERR_INVALADDRESSID;
  277. }
  278. lpAddressCaps->dwNeededSize =
  279. lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS);
  280. lpAddressCaps->dwLineDeviceID = dwDeviceID;
  281. lpAddressCaps->dwAddressSharing = LINEADDRESSSHARING_PRIVATE;
  282. lpAddressCaps->dwCallInfoStates = LINECALLINFOSTATE_MEDIAMODE |
  283. LINECALLINFOSTATE_APPSPECIFIC;
  284. lpAddressCaps->dwCallerIDFlags =
  285. lpAddressCaps->dwCalledIDFlags =
  286. lpAddressCaps->dwRedirectionIDFlags =
  287. lpAddressCaps->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
  288. lpAddressCaps->dwCallStates = LINECALLSTATE_IDLE |
  289. LINECALLSTATE_OFFERING |
  290. LINECALLSTATE_ACCEPTED |
  291. LINECALLSTATE_DIALTONE |
  292. LINECALLSTATE_DIALING |
  293. LINECALLSTATE_CONNECTED |
  294. LINECALLSTATE_PROCEEDING |
  295. LINECALLSTATE_DISCONNECTED |
  296. LINECALLSTATE_UNKNOWN;
  297. lpAddressCaps->dwDialToneModes = LINEDIALTONEMODE_UNAVAIL;
  298. lpAddressCaps->dwBusyModes = LINEBUSYMODE_UNAVAIL;
  299. lpAddressCaps->dwSpecialInfo = LINESPECIALINFO_UNAVAIL;
  300. lpAddressCaps->dwDisconnectModes = LINEDISCONNECTMODE_NORMAL |
  301. LINEDISCONNECTMODE_BUSY |
  302. LINEDISCONNECTMODE_NOANSWER |
  303. LINEDISCONNECTMODE_UNAVAIL |
  304. LINEDISCONNECTMODE_NODIALTONE;
  305. lpAddressCaps->dwMaxNumActiveCalls = 1;
  306. lpAddressCaps->dwAddrCapFlags = LINEADDRCAPFLAGS_DIALED;
  307. lpAddressCaps->dwCallFeatures = LINECALLFEATURE_ACCEPT |
  308. LINECALLFEATURE_ANSWER |
  309. LINECALLFEATURE_DROP |
  310. LINECALLFEATURE_SETCALLPARAMS;
  311. lpAddressCaps->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
  312. return (Epilog (&info, lResult));
  313. }
  314. LONG
  315. TSPIAPI
  316. TSPI_lineGetAddressStatus(
  317. HDRVLINE hdLine,
  318. DWORD dwAddressID,
  319. LPLINEADDRESSSTATUS lpAddressStatus
  320. )
  321. {
  322. #if DBG
  323. FUNC_PARAM params[] =
  324. {
  325. { gszhdLine, hdLine },
  326. { "dwAddressID", dwAddressID },
  327. { "lpAddressStatus", lpAddressStatus }
  328. };
  329. FUNC_INFO info =
  330. {
  331. "TSPI_lineGetAddressStatus",
  332. 3,
  333. params
  334. };
  335. #endif
  336. LONG lResult = 0;
  337. PDRVLINE pLine = (PDRVLINE) hdLine;
  338. Prolog (&info);
  339. lpAddressStatus->dwNeededSize =
  340. lpAddressStatus->dwUsedSize = sizeof(LINEADDRESSSTATUS);
  341. lpAddressStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0);
  342. lpAddressStatus->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
  343. return (Epilog (&info, lResult));
  344. }
  345. LONG
  346. TSPIAPI
  347. TSPI_lineGetCallAddressID(
  348. HDRVCALL hdCall,
  349. LPDWORD lpdwAddressID
  350. )
  351. {
  352. #if DBG
  353. FUNC_PARAM params[] =
  354. {
  355. { gszhdCall, hdCall },
  356. { "lpdwAddressID", lpdwAddressID }
  357. };
  358. FUNC_INFO info =
  359. {
  360. "TSPI_lineGetCallAddressID",
  361. 2,
  362. params
  363. };
  364. #endif
  365. //
  366. // We only support 1 address (id=0)
  367. //
  368. Prolog (&info);
  369. *lpdwAddressID = 0;
  370. return (Epilog (&info, 0));
  371. }
  372. LONG
  373. TSPIAPI
  374. TSPI_lineGetCallInfo(
  375. HDRVCALL hdCall,
  376. LPLINECALLINFO lpLineInfo
  377. )
  378. {
  379. #if DBG
  380. FUNC_PARAM params[] =
  381. {
  382. { gszhdCall, hdCall },
  383. { "lpLineInfo", lpLineInfo }
  384. };
  385. FUNC_INFO info =
  386. {
  387. "TSPI_lineGetCallInfo",
  388. 2,
  389. params
  390. };
  391. #endif
  392. LONG lResult = 0;
  393. PDRVLINE pLine = (PDRVLINE) hdCall;
  394. Prolog (&info);
  395. lpLineInfo->dwNeededSize =
  396. lpLineInfo->dwUsedSize = sizeof(LINECALLINFO);
  397. lpLineInfo->dwBearerMode = LINEBEARERMODE_VOICE;
  398. lpLineInfo->dwMediaMode = pLine->dwMediaMode;
  399. lpLineInfo->dwCallStates = LINECALLSTATE_IDLE |
  400. LINECALLSTATE_DIALTONE |
  401. LINECALLSTATE_DIALING |
  402. LINECALLSTATE_CONNECTED |
  403. LINECALLSTATE_PROCEEDING |
  404. LINECALLSTATE_DISCONNECTED |
  405. LINECALLSTATE_UNKNOWN;
  406. lpLineInfo->dwOrigin = LINECALLORIGIN_OUTBOUND;
  407. lpLineInfo->dwReason = LINECALLREASON_DIRECT;
  408. lpLineInfo->dwCallerIDFlags =
  409. lpLineInfo->dwCalledIDFlags =
  410. lpLineInfo->dwConnectedIDFlags =
  411. lpLineInfo->dwRedirectionIDFlags =
  412. lpLineInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
  413. return (Epilog (&info, lResult));
  414. }
  415. LONG
  416. TSPIAPI
  417. TSPI_lineGetCallStatus(
  418. HDRVCALL hdCall,
  419. LPLINECALLSTATUS lpLineStatus
  420. )
  421. {
  422. #if DBG
  423. FUNC_PARAM params[] =
  424. {
  425. { gszhdCall, hdCall },
  426. { "lpLineStatus", lpLineStatus }
  427. };
  428. FUNC_INFO info =
  429. {
  430. "TSPI_lineGetCallStatus",
  431. 2,
  432. params
  433. };
  434. #endif
  435. LONG lResult = 0;
  436. PDRVLINE pLine = (PDRVLINE) hdCall;
  437. Prolog (&info);
  438. lpLineStatus->dwNeededSize =
  439. lpLineStatus->dwUsedSize = sizeof(LINECALLSTATUS);
  440. lpLineStatus->dwCallState = pLine->dwCallState;
  441. if (pLine->dwCallState != LINECALLSTATE_IDLE)
  442. {
  443. lpLineStatus->dwCallFeatures = LINECALLFEATURE_DROP;
  444. }
  445. return (Epilog (&info, lResult));
  446. }
  447. LONG
  448. TSPIAPI
  449. TSPI_lineGetDevCaps(
  450. DWORD dwDeviceID,
  451. DWORD dwTSPIVersion,
  452. DWORD dwExtVersion,
  453. LPLINEDEVCAPS lpLineDevCaps
  454. )
  455. {
  456. #if DBG
  457. FUNC_PARAM params[] =
  458. {
  459. { gszdwDeviceID, dwDeviceID },
  460. { "dwTSPIVersion", dwTSPIVersion },
  461. { "dwExtVersion", dwExtVersion },
  462. { "lpLineDevCaps", lpLineDevCaps }
  463. };
  464. FUNC_INFO info =
  465. {
  466. "TSPI_lineGetDevCaps",
  467. 4,
  468. params
  469. };
  470. #endif
  471. LONG lResult = 0;
  472. static WCHAR szProviderInfo[] = L"AT-compatible modem service provider";
  473. #define PROVIDER_INFO_SIZE (37 * sizeof (WCHAR))
  474. Prolog (&info);
  475. lpLineDevCaps->dwNeededSize = sizeof (LINEDEVCAPS) + PROVIDER_INFO_SIZE +
  476. (MAX_DEV_NAME_LENGTH + 1) * sizeof (WCHAR);
  477. if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwNeededSize)
  478. {
  479. #define LINECONFIG_SIZE (2 * (MAX_DEV_NAME_LENGTH + 1) + 40)
  480. char szLineConfig[LINECONFIG_SIZE], szLineN[16], *p;
  481. HKEY hKey;
  482. DWORD dwDataSize, dwDataType;
  483. lpLineDevCaps->dwUsedSize = lpLineDevCaps->dwNeededSize;
  484. lpLineDevCaps->dwProviderInfoSize = PROVIDER_INFO_SIZE;
  485. lpLineDevCaps->dwProviderInfoOffset = sizeof(LINEDEVCAPS);
  486. My_lstrcpyW ((WCHAR *)(lpLineDevCaps + 1), szProviderInfo);
  487. RegOpenKeyEx(
  488. HKEY_LOCAL_MACHINE,
  489. gszAtspKey,
  490. 0,
  491. KEY_ALL_ACCESS,
  492. &hKey
  493. );
  494. dwDataSize = LINECONFIG_SIZE;
  495. wsprintf (szLineN, "Line%d", dwDeviceID - gdwLineDeviceIDBase);
  496. lstrcpy (szLineConfig, gszDefLineConfigParams);
  497. RegQueryValueEx(
  498. hKey,
  499. szLineN,
  500. 0,
  501. &dwDataType,
  502. (LPBYTE) szLineConfig,
  503. &dwDataSize
  504. );
  505. RegCloseKey (hKey);
  506. for (p = szLineConfig; *p != ','; p++);
  507. *p = 0;
  508. lpLineDevCaps->dwLineNameSize = (lstrlen (szLineConfig) + 1) *
  509. sizeof (WCHAR);
  510. lpLineDevCaps->dwLineNameOffset = sizeof(LINEDEVCAPS) +
  511. PROVIDER_INFO_SIZE;
  512. MultiByteToWideChar(
  513. CP_ACP,
  514. MB_PRECOMPOSED,
  515. szLineConfig,
  516. -1,
  517. (WCHAR *) ((LPBYTE) (lpLineDevCaps + 1) + PROVIDER_INFO_SIZE),
  518. lpLineDevCaps->dwLineNameSize
  519. );
  520. }
  521. else
  522. {
  523. lpLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS);
  524. }
  525. lpLineDevCaps->dwStringFormat = STRINGFORMAT_ASCII;
  526. lpLineDevCaps->dwAddressModes = LINEADDRESSMODE_ADDRESSID;
  527. lpLineDevCaps->dwNumAddresses = 1;
  528. lpLineDevCaps->dwBearerModes = LINEBEARERMODE_VOICE;
  529. lpLineDevCaps->dwMaxRate = 9600;
  530. lpLineDevCaps->dwMediaModes = LINEMEDIAMODE_INTERACTIVEVOICE |
  531. LINEMEDIAMODE_DATAMODEM;
  532. lpLineDevCaps->dwDevCapFlags = LINEDEVCAPFLAGS_CLOSEDROP |
  533. LINEDEVCAPFLAGS_DIALBILLING |
  534. LINEDEVCAPFLAGS_DIALQUIET |
  535. LINEDEVCAPFLAGS_DIALDIALTONE;
  536. lpLineDevCaps->dwMaxNumActiveCalls = 1;
  537. lpLineDevCaps->dwRingModes = 1;
  538. lpLineDevCaps->dwLineFeatures = LINEFEATURE_MAKECALL;
  539. return (Epilog (&info, lResult));
  540. }
  541. LONG
  542. TSPIAPI
  543. TSPI_lineGetID(
  544. HDRVLINE hdLine,
  545. DWORD dwAddressID,
  546. HDRVCALL hdCall,
  547. DWORD dwSelect,
  548. LPVARSTRING lpDeviceID,
  549. LPCWSTR lpszDeviceClass,
  550. HANDLE hTargetProcess
  551. )
  552. {
  553. #if DBG
  554. FUNC_PARAM params[] =
  555. {
  556. { gszhdLine, hdLine },
  557. { "dwAddressID", dwAddressID },
  558. { gszhdCall, hdCall },
  559. { "dwSelect", dwSelect },
  560. { "lpDeviceID", lpDeviceID },
  561. { "lpszDeviceClass", lpszDeviceClass },
  562. { "hTargetProcess", hTargetProcess }
  563. };
  564. FUNC_INFO info =
  565. {
  566. "TSPI_lineGetID",
  567. 7,
  568. params
  569. };
  570. #endif
  571. DWORD dwNeededSize = sizeof(VARSTRING) + sizeof (DWORD);
  572. LONG lResult = 0;
  573. PDRVLINE pLine = (dwSelect == LINECALLSELECT_CALL ?
  574. (PDRVLINE) hdCall : (PDRVLINE) hdLine);
  575. Prolog (&info);
  576. if (lstrcmpiW (lpszDeviceClass, L"tapi/line") == 0)
  577. {
  578. if (lpDeviceID->dwTotalSize < dwNeededSize)
  579. {
  580. lpDeviceID->dwUsedSize = 3*sizeof(DWORD);
  581. }
  582. else
  583. {
  584. lpDeviceID->dwUsedSize = dwNeededSize;
  585. lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY;
  586. lpDeviceID->dwStringSize = sizeof(DWORD);
  587. lpDeviceID->dwStringOffset = sizeof(VARSTRING);
  588. *((LPDWORD)(lpDeviceID + 1)) = pLine->dwDeviceID;
  589. }
  590. lpDeviceID->dwNeededSize = dwNeededSize;
  591. }
  592. else if (lstrcmpiW (lpszDeviceClass, L"comm/datamodem") == 0)
  593. {
  594. dwNeededSize += (strlen (pLine->szComm) + 1) * sizeof (WCHAR);
  595. if (lpDeviceID->dwTotalSize < dwNeededSize)
  596. {
  597. lpDeviceID->dwUsedSize = 3 * sizeof(DWORD);
  598. }
  599. else
  600. {
  601. HANDLE hCommDup = NULL;
  602. if (!pLine->htCall)
  603. {
  604. DBGOUT((1, "TSPI_lineGetID32: error, no active call"));
  605. lResult = LINEERR_OPERATIONFAILED;
  606. goto TSPI_lineGetID_epilog;
  607. }
  608. if (!DuplicateHandle(
  609. GetCurrentProcess(),
  610. pLine->hComm,
  611. hTargetProcess,
  612. &hCommDup,
  613. 0,
  614. TRUE,
  615. DUPLICATE_SAME_ACCESS
  616. ))
  617. {
  618. DBGOUT((
  619. 1,
  620. "TSPI_lineGetID: DupHandle failed, err=%ld",
  621. GetLastError()
  622. ));
  623. lResult = LINEERR_OPERATIONFAILED;
  624. goto TSPI_lineGetID_epilog;
  625. }
  626. lpDeviceID->dwUsedSize = dwNeededSize;
  627. lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY;
  628. lpDeviceID->dwStringSize = dwNeededSize - sizeof(VARSTRING);
  629. lpDeviceID->dwStringOffset = sizeof(VARSTRING);
  630. *((HANDLE *)(lpDeviceID + 1)) = hCommDup;
  631. lstrcpy(
  632. ((char *)(lpDeviceID + 1)) + sizeof (HANDLE),
  633. pLine->szComm
  634. );
  635. MultiByteToWideChar(
  636. CP_ACP,
  637. 0,
  638. pLine->szComm,
  639. -1,
  640. ((WCHAR *)(lpDeviceID + 1)) + sizeof (HANDLE),
  641. 256
  642. );
  643. }
  644. lpDeviceID->dwNeededSize = dwNeededSize;
  645. }
  646. else
  647. {
  648. lResult = LINEERR_NODEVICE;
  649. }
  650. TSPI_lineGetID_epilog:
  651. return (Epilog (&info, lResult));
  652. }
  653. LONG
  654. TSPIAPI
  655. TSPI_lineGetLineDevStatus(
  656. HDRVLINE hdLine,
  657. LPLINEDEVSTATUS lpLineDevStatus
  658. )
  659. {
  660. #if DBG
  661. FUNC_PARAM params[] =
  662. {
  663. { gszhdLine, hdLine },
  664. { "lpLineDevStatus", lpLineDevStatus }
  665. };
  666. FUNC_INFO info =
  667. {
  668. "TSPI_lineGetLineDevStatus",
  669. 2,
  670. params
  671. };
  672. #endif
  673. LONG lResult = 0;
  674. PDRVLINE pLine = (PDRVLINE) hdLine;
  675. Prolog (&info);
  676. lpLineDevStatus->dwUsedSize =
  677. lpLineDevStatus->dwNeededSize = sizeof (LINEDEVSTATUS);
  678. lpLineDevStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0);
  679. //lpLineDevStatus->dwLineFeatures =
  680. lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED |
  681. LINEDEVSTATUSFLAGS_INSERVICE;
  682. return (Epilog (&info, lResult));
  683. }
  684. LONG
  685. TSPIAPI
  686. TSPI_lineGetNumAddressIDs(
  687. HDRVLINE hdLine,
  688. LPDWORD lpdwNumAddressIDs
  689. )
  690. {
  691. #if DBG
  692. FUNC_PARAM params[] =
  693. {
  694. { gszhdLine, hdLine },
  695. { "lpdwNumAddressIDs", lpdwNumAddressIDs }
  696. };
  697. FUNC_INFO info =
  698. {
  699. "TSPI_lineGetNumAddressIDs",
  700. 2,
  701. params
  702. };
  703. #endif
  704. LONG lResult = 0;
  705. PDRVLINE pLine = (PDRVLINE) hdLine;
  706. //
  707. // We only support 1 address (id=0)
  708. //
  709. Prolog (&info);
  710. *lpdwNumAddressIDs = 1;
  711. return (Epilog (&info, lResult));
  712. }
  713. LONG
  714. TSPIAPI
  715. TSPI_lineMakeCall(
  716. DRV_REQUESTID dwRequestID,
  717. HDRVLINE hdLine,
  718. HTAPICALL htCall,
  719. LPHDRVCALL lphdCall,
  720. LPCWSTR lpszDestAddress,
  721. DWORD dwCountryCode,
  722. LPLINECALLPARAMS const lpCallParams
  723. )
  724. {
  725. char szCommands[64], szCommand[64], szDestAddress[128];
  726. DWORD dwThreadID, dwNumBytes, dwError;
  727. PDRVLINE pLine = (PDRVLINE) hdLine;
  728. #if DBG
  729. FUNC_PARAM params[] =
  730. {
  731. { gszdwRequestID, dwRequestID },
  732. { gszhdLine, hdLine },
  733. { "htCall", htCall },
  734. { "lphdCall", lphdCall },
  735. { "lpszDestAddress", szDestAddress },
  736. { "dwCountryCode", dwCountryCode },
  737. { gszlpCallParams, lpCallParams }
  738. };
  739. FUNC_INFO info =
  740. {
  741. "TSPI_lineMakeCall",
  742. 7,
  743. params
  744. };
  745. #endif
  746. if (lpszDestAddress)
  747. {
  748. WideCharToMultiByte(
  749. CP_ACP,
  750. 0,
  751. lpszDestAddress,
  752. -1,
  753. (LPSTR) szDestAddress,
  754. 128,
  755. NULL,
  756. NULL
  757. );
  758. }
  759. Prolog (&info);
  760. //
  761. // Check to see if there's already another call
  762. //
  763. if (pLine->htCall)
  764. {
  765. (*gpfnCompletionProc)(dwRequestID, LINEERR_CALLUNAVAIL);
  766. goto TSPI_lineMakeCall_return;
  767. }
  768. //
  769. // Since we don't support TSPI_lineDial, fail if app tries
  770. // to pass a NULL lpszDestAddress (implying that app just
  771. // wants to go offhook)
  772. //
  773. if (lpszDestAddress == NULL)
  774. {
  775. (*gpfnCompletionProc)(dwRequestID, LINEERR_INVALADDRESS);
  776. goto TSPI_lineMakeCall_return;
  777. }
  778. //
  779. // Get the line's config info
  780. //
  781. {
  782. HKEY hKey;
  783. DWORD dwDataSize, dwDataType;
  784. char szLineN[8], *pszConfig, *p, *p2;
  785. wsprintf(
  786. szLineN,
  787. "Line%d",
  788. ((PDRVLINE) hdLine)->dwDeviceID - gdwLineDeviceIDBase
  789. );
  790. dwDataSize = 256;
  791. pszConfig = DrvAlloc (dwDataSize);
  792. RegOpenKeyEx(
  793. HKEY_LOCAL_MACHINE,
  794. gszAtspKey,
  795. 0,
  796. KEY_ALL_ACCESS,
  797. &hKey
  798. );
  799. RegQueryValueEx(
  800. hKey,
  801. szLineN,
  802. 0,
  803. &dwDataType,
  804. (LPBYTE) pszConfig,
  805. &dwDataSize
  806. );
  807. pszConfig[dwDataSize] = '\0'; // *pszConfig = "MyLine,COM1,L0"
  808. RegCloseKey (hKey);
  809. //
  810. // szComm
  811. //
  812. for (p = pszConfig; *p != ','; p++);
  813. p++; // *p = "COM1,L0"
  814. for (p2 = p; *p2 != ','; p2++);
  815. *p2 = 0; // *p = "COM1"
  816. lstrcpy (pLine->szComm, p);
  817. //
  818. // szCommands
  819. //
  820. p2++; // *p2 = "L0"
  821. lstrcpy (szCommands, p2);
  822. DrvFree (pszConfig);
  823. }
  824. //
  825. // Open the port
  826. //
  827. if ((pLine->hComm = CreateFile(
  828. pLine->szComm,
  829. GENERIC_READ | GENERIC_WRITE,
  830. 0, //FILE_SHARE_READ | FILE_SHARE_WRITE,
  831. NULL, // no security attrs
  832. OPEN_EXISTING,
  833. FILE_FLAG_OVERLAPPED,
  834. NULL // no template file
  835. )) == INVALID_HANDLE_VALUE)
  836. {
  837. DBGOUT((
  838. 3,
  839. "TSPI_lineMakeCall: CreateFile(%s) failed, err=%ld",
  840. pLine->szComm,
  841. GetLastError()
  842. ));
  843. (*gpfnCompletionProc)(dwRequestID, LINEERR_RESOURCEUNAVAIL);
  844. goto TSPI_lineMakeCall_return;
  845. }
  846. //
  847. // Setup up the modem command string. If there's an initial 'T'
  848. // or 'P' (for Tone or Pulse) in the dest address then disregard
  849. // it. Also if it's a voice call add the semi colon so we return
  850. // to cmd mode.
  851. //
  852. {
  853. char *p = (char *) szDestAddress;
  854. if (*p == 'T' || *p == 'P')
  855. {
  856. p++;
  857. }
  858. if (lpCallParams &&
  859. lpCallParams->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE)
  860. {
  861. wsprintf (szCommand, "AT%sDT%s\r", szCommands, p);
  862. }
  863. else
  864. {
  865. wsprintf (szCommand, "AT%sDT%s;\r", szCommands, p);
  866. }
  867. }
  868. //
  869. // Init the data structure & tell tapi our handle to the call
  870. //
  871. pLine->htCall = htCall;
  872. pLine->bDropInProgress = FALSE;
  873. pLine->dwMediaMode = (lpCallParams ? lpCallParams->dwMediaMode :
  874. LINEMEDIAMODE_INTERACTIVEVOICE);
  875. *lphdCall = (HDRVCALL) pLine;
  876. //
  877. // Do an overlapped write, the comm thread will deal with the results
  878. //
  879. pLine->Overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  880. if (!WriteFile(
  881. pLine->hComm,
  882. szCommand,
  883. lstrlen (szCommand),
  884. &dwNumBytes,
  885. &pLine->Overlapped
  886. )
  887. && (dwError = GetLastError()) != ERROR_IO_PENDING)
  888. {
  889. DBGOUT((
  890. 1,
  891. "TSPI_lineMakeCall: WriteFile(%s) failed, error=%d",
  892. pLine->szComm,
  893. dwError
  894. ));
  895. pLine->htCall = NULL;
  896. CloseHandle (pLine->hComm);
  897. CloseHandle (pLine->Overlapped.hEvent);
  898. (*gpfnCompletionProc)(dwRequestID, LINEERR_OPERATIONFAILED);
  899. goto TSPI_lineMakeCall_return;
  900. }
  901. //
  902. // Complete the requests & set the initial call state
  903. //
  904. (*gpfnCompletionProc)(dwRequestID, 0);
  905. SetCallState (pLine, LINECALLSTATE_DIALING, 0);
  906. //
  907. // Spin the comm thread to handle the results of the Write above
  908. //
  909. {
  910. HANDLE hCommThread;
  911. if (!(hCommThread = CreateThread(
  912. (LPSECURITY_ATTRIBUTES) NULL,
  913. 0,
  914. (LPTHREAD_START_ROUTINE) CommThread,
  915. pLine,
  916. 0,
  917. &dwThreadID
  918. )))
  919. {
  920. DBGOUT((
  921. 1,
  922. "TSPI_lineMakeCall: CreateThread failed, err=%ld",
  923. GetLastError()
  924. ));
  925. GetOverlappedResult(
  926. pLine->hComm,
  927. &pLine->Overlapped,
  928. &dwNumBytes,
  929. TRUE
  930. );
  931. SetCallState (pLine, LINECALLSTATE_IDLE, 0);
  932. CloseHandle (pLine->hComm);
  933. CloseHandle (pLine->Overlapped.hEvent);
  934. goto TSPI_lineMakeCall_return;
  935. }
  936. CloseHandle (hCommThread);
  937. }
  938. TSPI_lineMakeCall_return:
  939. return (Epilog (&info, dwRequestID));
  940. }
  941. LONG
  942. TSPIAPI
  943. TSPI_lineNegotiateTSPIVersion(
  944. DWORD dwDeviceID,
  945. DWORD dwLowVersion,
  946. DWORD dwHighVersion,
  947. LPDWORD lpdwTSPIVersion
  948. )
  949. {
  950. LONG lResult = 0;
  951. #if DBG
  952. FUNC_PARAM params[] =
  953. {
  954. { gszdwDeviceID, dwDeviceID },
  955. { "dwLowVersion", dwLowVersion },
  956. { "dwHighVersion", dwHighVersion },
  957. { "lpdwTSPIVersion", lpdwTSPIVersion }
  958. };
  959. FUNC_INFO info =
  960. {
  961. "TSPI_lineNegotiateTSPIVersion",
  962. 4,
  963. params
  964. };
  965. #endif
  966. Prolog (&info);
  967. *lpdwTSPIVersion = 0x00020000;
  968. return (Epilog (&info, lResult));
  969. }
  970. LONG
  971. TSPIAPI
  972. TSPI_lineOpen(
  973. DWORD dwDeviceID,
  974. HTAPILINE htLine,
  975. LPHDRVLINE lphdLine,
  976. DWORD dwTSPIVersion,
  977. LINEEVENT lpfnEventProc
  978. )
  979. {
  980. LONG lResult;
  981. PDRVLINE pLine;
  982. #if DBG
  983. FUNC_PARAM params[] =
  984. {
  985. { gszdwDeviceID, dwDeviceID },
  986. { "htLine", htLine },
  987. { "lphdLine", lphdLine },
  988. { "dwTSPIVersion", dwTSPIVersion },
  989. { "lpfnEventProc", lpfnEventProc }
  990. };
  991. FUNC_INFO info =
  992. {
  993. "TSPI_lineOpen",
  994. 5,
  995. params
  996. };
  997. #endif
  998. Prolog (&info);
  999. if ((pLine = DrvAlloc (sizeof (DRVLINE))))
  1000. {
  1001. pLine->htLine = htLine;
  1002. pLine->pfnEventProc = lpfnEventProc;
  1003. pLine->dwDeviceID = dwDeviceID;
  1004. *lphdLine = (HDRVLINE) pLine;
  1005. lResult = 0;
  1006. }
  1007. else
  1008. {
  1009. lResult = LINEERR_NOMEM;
  1010. }
  1011. return (Epilog (&info, lResult));
  1012. }
  1013. LONG
  1014. TSPIAPI
  1015. TSPI_lineSetDefaultMediaDetection(
  1016. HDRVLINE hdLine,
  1017. DWORD dwMediaModes
  1018. )
  1019. {
  1020. #if DBG
  1021. FUNC_PARAM params[] =
  1022. {
  1023. { gszhdLine, hdLine },
  1024. { "dwMediaModes", dwMediaModes }
  1025. };
  1026. FUNC_INFO info =
  1027. {
  1028. "TSPI_lineSetDefaultMediaDetection",
  1029. 2,
  1030. params
  1031. };
  1032. #endif
  1033. //
  1034. // This func is really a no-op for us, since we don't look
  1035. // for incoming calls (though we do say we support them to
  1036. // make apps happy)
  1037. //
  1038. Prolog (&info);
  1039. return (Epilog (&info, 0));
  1040. }
  1041. //
  1042. // ------------------------- TSPI_providerXxx funcs ---------------------------
  1043. //
  1044. LONG
  1045. TSPIAPI
  1046. TSPI_providerConfig(
  1047. HWND hwndOwner,
  1048. DWORD dwPermanentProviderID
  1049. )
  1050. {
  1051. //
  1052. // Although this func is never called by TAPI v2.0, we export
  1053. // it so that the Telephony Control Panel Applet knows that it
  1054. // can configure this provider via lineConfigProvider(),
  1055. // otherwise Telephon.cpl will not consider it configurable
  1056. //
  1057. return 0;
  1058. }
  1059. LONG
  1060. TSPIAPI
  1061. TSPI_providerGenericDialogData(
  1062. ULONG_PTR dwObjectID,
  1063. DWORD dwObjectType,
  1064. LPVOID lpParams,
  1065. DWORD dwSize
  1066. )
  1067. {
  1068. LONG lResult = 0;
  1069. #if DBG
  1070. FUNC_PARAM params[] =
  1071. {
  1072. { "dwObjectID", dwObjectID },
  1073. { "dwObjectType", dwObjectType },
  1074. { "lpParams", lpParams },
  1075. { "dwSize", dwSize }
  1076. };
  1077. FUNC_INFO info =
  1078. {
  1079. "TSPI_providerGenericDialogData",
  1080. 4,
  1081. params
  1082. };
  1083. #endif
  1084. Prolog (&info);
  1085. return (Epilog (&info, lResult));
  1086. }
  1087. LONG
  1088. TSPIAPI
  1089. TSPI_providerInit(
  1090. DWORD dwTSPIVersion,
  1091. DWORD dwPermanentProviderID,
  1092. DWORD dwLineDeviceIDBase,
  1093. DWORD dwPhoneDeviceIDBase,
  1094. DWORD_PTR dwNumLines,
  1095. DWORD_PTR dwNumPhones,
  1096. ASYNC_COMPLETION lpfnCompletionProc,
  1097. LPDWORD lpdwTSPIOptions
  1098. )
  1099. {
  1100. LONG lResult = 0;
  1101. #if DBG
  1102. FUNC_PARAM params[] =
  1103. {
  1104. { "dwTSPIVersion", dwTSPIVersion },
  1105. { gszdwPermanentProviderID, dwPermanentProviderID },
  1106. { "dwLineDeviceIDBase", dwLineDeviceIDBase },
  1107. { "dwPhoneDeviceIDBase", dwPhoneDeviceIDBase },
  1108. { "dwNumLines", dwNumLines },
  1109. { "dwNumPhones", dwNumPhones },
  1110. { "lpfnCompletionProc", lpfnCompletionProc }
  1111. };
  1112. FUNC_INFO info =
  1113. {
  1114. "TSPI_providerInit",
  1115. 7,
  1116. params
  1117. };
  1118. #endif
  1119. Prolog (&info);
  1120. gdwLineDeviceIDBase = dwLineDeviceIDBase;
  1121. gpfnCompletionProc = lpfnCompletionProc;
  1122. *lpdwTSPIOptions = LINETSPIOPTION_NONREENTRANT;
  1123. return (Epilog (&info, lResult));
  1124. }
  1125. LONG
  1126. TSPIAPI
  1127. TSPI_providerInstall(
  1128. HWND hwndOwner,
  1129. DWORD dwPermanentProviderID
  1130. )
  1131. {
  1132. //
  1133. // Although this func is never called by TAPI v2.0, we export
  1134. // it so that the Telephony Control Panel Applet knows that it
  1135. // can add this provider via lineAddProvider(), otherwise
  1136. // Telephon.cpl will not consider it installable
  1137. //
  1138. //
  1139. return 0;
  1140. }
  1141. LONG
  1142. TSPIAPI
  1143. TSPI_providerRemove(
  1144. HWND hwndOwner,
  1145. DWORD dwPermanentProviderID
  1146. )
  1147. {
  1148. //
  1149. // Although this func is never called by TAPI v2.0, we export
  1150. // it so that the Telephony Control Panel Applet knows that it
  1151. // can remove this provider via lineRemoveProvider(), otherwise
  1152. // Telephon.cpl will not consider it removable
  1153. //
  1154. return 0;
  1155. }
  1156. LONG
  1157. TSPIAPI
  1158. TSPI_providerShutdown(
  1159. DWORD dwTSPIVersion,
  1160. DWORD dwPermanentProviderID
  1161. )
  1162. {
  1163. LONG lResult = 0;
  1164. #if DBG
  1165. FUNC_PARAM params[] =
  1166. {
  1167. { "dwTSPIVersion", dwTSPIVersion },
  1168. { gszdwPermanentProviderID, dwPermanentProviderID }
  1169. };
  1170. FUNC_INFO info =
  1171. {
  1172. "TSPI_providerShutdown",
  1173. 2,
  1174. params
  1175. };
  1176. #endif
  1177. Prolog (&info);
  1178. return (Epilog (&info, lResult));
  1179. }
  1180. LONG
  1181. TSPIAPI
  1182. TSPI_providerEnumDevices(
  1183. DWORD dwPermanentProviderID,
  1184. LPDWORD lpdwNumLines,
  1185. LPDWORD lpdwNumPhones,
  1186. HPROVIDER hProvider,
  1187. LINEEVENT lpfnLineCreateProc,
  1188. PHONEEVENT lpfnPhoneCreateProc
  1189. )
  1190. {
  1191. HKEY hKey;
  1192. DWORD dwNumLines, dwDataType, dwDataSize;
  1193. //
  1194. // Retrieve the number of devices we're
  1195. // configured for from our registry section
  1196. //
  1197. if (ERROR_SUCCESS !=
  1198. RegOpenKeyEx(
  1199. HKEY_LOCAL_MACHINE,
  1200. gszAtspKey,
  1201. 0,
  1202. KEY_ALL_ACCESS,
  1203. &hKey
  1204. ))
  1205. {
  1206. return LINEERR_OPERATIONFAILED;
  1207. }
  1208. dwDataSize = sizeof(dwNumLines);
  1209. dwNumLines = 0;
  1210. RegQueryValueEx(
  1211. hKey,
  1212. gszNumLines,
  1213. 0,
  1214. &dwDataType,
  1215. (LPBYTE) &dwNumLines,
  1216. &dwDataSize
  1217. );
  1218. RegCloseKey (hKey);
  1219. *lpdwNumLines = dwNumLines;
  1220. *lpdwNumPhones = 0;
  1221. return 0;
  1222. }
  1223. LONG
  1224. TSPIAPI
  1225. TSPI_providerUIIdentify(
  1226. LPWSTR lpszUIDLLName
  1227. )
  1228. {
  1229. LONG lResult = 0;
  1230. #if DBG
  1231. FUNC_PARAM params[] =
  1232. {
  1233. { "lpsUIDLLName", lpszUIDLLName }
  1234. };
  1235. FUNC_INFO info =
  1236. {
  1237. "TSPI_providerUIIdentify",
  1238. 1,
  1239. params
  1240. };
  1241. #endif
  1242. Prolog (&info);
  1243. My_lstrcpyW(lpszUIDLLName, L"atsp32.tsp");
  1244. return (Epilog (&info, lResult));
  1245. }
  1246. //
  1247. // ---------------------------- TUISPI_xxx funcs ------------------------------
  1248. //
  1249. LONG
  1250. TSPIAPI
  1251. TUISPI_lineConfigDialog(
  1252. TUISPIDLLCALLBACK lpfnUIDLLCallback,
  1253. DWORD dwDeviceID,
  1254. HWND hwndOwner,
  1255. LPCWSTR lpszDeviceClass
  1256. )
  1257. {
  1258. char szDeviceClass[128];
  1259. LONG lResult = 0;
  1260. #if DBG
  1261. FUNC_PARAM params[] =
  1262. {
  1263. { "lpfnUIDLLCallback", lpfnUIDLLCallback },
  1264. { gszdwDeviceID, dwDeviceID },
  1265. { gszhwndOwner, hwndOwner },
  1266. { "lpszDeviceClass", szDeviceClass }
  1267. };
  1268. FUNC_INFO info =
  1269. {
  1270. "TUISPI_lineConfigDialog",
  1271. 4,
  1272. params
  1273. };
  1274. #endif
  1275. if (lpszDeviceClass)
  1276. {
  1277. WideCharToMultiByte(
  1278. CP_ACP,
  1279. 0,
  1280. lpszDeviceClass,
  1281. -1,
  1282. (LPSTR) szDeviceClass,
  1283. 128,
  1284. NULL,
  1285. NULL
  1286. );
  1287. }
  1288. Prolog (&info);
  1289. DialogBoxParam(
  1290. ghInst,
  1291. MAKEINTRESOURCE(IDD_DIALOG1),
  1292. hwndOwner,
  1293. (DLGPROC) ConfigDlgProc,
  1294. 0
  1295. );
  1296. return (Epilog (&info, lResult));
  1297. }
  1298. LONG
  1299. TSPIAPI
  1300. TUISPI_providerConfig(
  1301. TUISPIDLLCALLBACK lpfnUIDLLCallback,
  1302. HWND hwndOwner,
  1303. DWORD dwPermanentProviderID
  1304. )
  1305. {
  1306. LONG lResult = 0;
  1307. #if DBG
  1308. FUNC_PARAM params[] =
  1309. {
  1310. { "lpfnUIDLLCallback", lpfnUIDLLCallback },
  1311. { gszhwndOwner, hwndOwner },
  1312. { gszdwPermanentProviderID, dwPermanentProviderID }
  1313. };
  1314. FUNC_INFO info =
  1315. {
  1316. "TUISPI_providerConfig",
  1317. 3,
  1318. params
  1319. };
  1320. #endif
  1321. Prolog (&info);
  1322. DialogBoxParam(
  1323. ghInst,
  1324. MAKEINTRESOURCE(IDD_DIALOG1),
  1325. hwndOwner,
  1326. (DLGPROC) ConfigDlgProc,
  1327. 0
  1328. );
  1329. return (Epilog (&info, lResult));
  1330. }
  1331. LONG
  1332. TSPIAPI
  1333. TUISPI_providerInstall(
  1334. TUISPIDLLCALLBACK lpfnUIDLLCallback,
  1335. HWND hwndOwner,
  1336. DWORD dwPermanentProviderID
  1337. )
  1338. {
  1339. LONG lResult;
  1340. if ((lResult = ProviderInstall ("atsp32.tsp", TRUE)) == 0)
  1341. {
  1342. DialogBoxParam(
  1343. ghInst,
  1344. MAKEINTRESOURCE(IDD_DIALOG1),
  1345. hwndOwner,
  1346. (DLGPROC) ConfigDlgProc,
  1347. 0
  1348. );
  1349. }
  1350. return lResult;
  1351. }
  1352. LONG
  1353. TSPIAPI
  1354. TUISPI_providerRemove(
  1355. TUISPIDLLCALLBACK lpfnUIDLLCallback,
  1356. HWND hwndOwner,
  1357. DWORD dwPermanentProviderID
  1358. )
  1359. {
  1360. HKEY hKey;
  1361. char szSoftwareMsft[] = "Software\\Microsoft", szATSP[] = "ATSP";
  1362. LONG lResult;
  1363. //
  1364. // Clean up our registry section
  1365. //
  1366. lResult = RegOpenKeyExA(
  1367. HKEY_LOCAL_MACHINE,
  1368. szSoftwareMsft,
  1369. 0,
  1370. KEY_ALL_ACCESS,
  1371. &hKey
  1372. );
  1373. if (ERROR_SUCCESS != lResult)
  1374. return 0;
  1375. RegDeleteKeyA (hKey, szATSP);
  1376. RegCloseKey (hKey);
  1377. return 0;
  1378. }
  1379. #pragma warning (default:4047)
  1380. //
  1381. // ---------------------- Misc private support routines -----------------------
  1382. //
  1383. LPWSTR
  1384. PASCAL
  1385. My_lstrcpyW(
  1386. WCHAR *pString1,
  1387. WCHAR *pString2
  1388. )
  1389. {
  1390. WCHAR *p = pString1;
  1391. for (; (*p = *pString2); p++, pString2++);
  1392. return pString1;
  1393. }
  1394. void
  1395. PASCAL
  1396. EnableChildren(
  1397. HWND hwnd,
  1398. BOOL bEnable
  1399. )
  1400. {
  1401. int i;
  1402. static int aiControlIDs[] =
  1403. {
  1404. IDC_DEVICES,
  1405. IDC_NAME,
  1406. IDC_PORT,
  1407. IDC_COMMANDS,
  1408. IDC_REMOVE,
  1409. 0
  1410. };
  1411. for (i = 0; aiControlIDs[i]; i++)
  1412. {
  1413. EnableWindow (GetDlgItem (hwnd, aiControlIDs[i]), bEnable);
  1414. }
  1415. }
  1416. void
  1417. PASCAL
  1418. SelectDevice(
  1419. HWND hwnd,
  1420. LRESULT lDevice
  1421. )
  1422. {
  1423. SendDlgItemMessage (hwnd, IDC_DEVICES, LB_SETCURSEL, lDevice, 0);
  1424. PostMessage(hwnd, WM_COMMAND, IDC_DEVICES | (LBN_SELCHANGE << 16), 0);
  1425. }
  1426. BOOL
  1427. CALLBACK
  1428. ConfigDlgProc(
  1429. HWND hwnd,
  1430. UINT msg,
  1431. WPARAM wParam,
  1432. LPARAM lParam
  1433. )
  1434. {
  1435. static HKEY hAtspKey;
  1436. DWORD dwDataSize;
  1437. DWORD dwDataType;
  1438. switch (msg)
  1439. {
  1440. case WM_INITDIALOG:
  1441. {
  1442. char *pBuf;
  1443. DWORD i, iNumLines;
  1444. //
  1445. // Create or open our configuration key in the registry. If the
  1446. // create fails it may well be that the current user does not
  1447. // have write access to this portion of the registry, so we'll
  1448. // just show a "read only" dialog and not allow user to make any
  1449. // changes
  1450. //
  1451. {
  1452. LONG lResult;
  1453. DWORD dwDisposition;
  1454. if ((lResult = RegCreateKeyEx(
  1455. HKEY_LOCAL_MACHINE,
  1456. gszAtspKey,
  1457. 0,
  1458. "",
  1459. REG_OPTION_NON_VOLATILE,
  1460. KEY_ALL_ACCESS,
  1461. (LPSECURITY_ATTRIBUTES) NULL,
  1462. &hAtspKey,
  1463. &dwDisposition
  1464. )) != ERROR_SUCCESS)
  1465. {
  1466. DBGOUT((
  1467. 3,
  1468. "RegCreateKeyEx(%s,ALL_ACCESS) failed, err=%d",
  1469. gszAtspKey,
  1470. lResult
  1471. ));
  1472. if ((lResult = RegOpenKeyEx(
  1473. HKEY_LOCAL_MACHINE,
  1474. gszAtspKey,
  1475. 0,
  1476. KEY_QUERY_VALUE,
  1477. &hAtspKey
  1478. )) != ERROR_SUCCESS)
  1479. {
  1480. DBGOUT((
  1481. 3,
  1482. "RegOpenKeyEx(%s,ALL_ACCESS) failed, err=%d",
  1483. gszAtspKey,
  1484. lResult
  1485. ));
  1486. EndDialog (hwnd, 0);
  1487. return FALSE;
  1488. }
  1489. {
  1490. int i;
  1491. static int aiControlIDs[] =
  1492. {
  1493. IDC_NAME,
  1494. IDC_PORT,
  1495. IDC_COMMANDS,
  1496. IDC_ADD,
  1497. IDC_REMOVE,
  1498. IDOK,
  1499. 0
  1500. };
  1501. for (i = 0; aiControlIDs[i]; i++)
  1502. {
  1503. EnableWindow(
  1504. GetDlgItem (hwnd, aiControlIDs[i]),
  1505. FALSE
  1506. );
  1507. }
  1508. }
  1509. }
  1510. }
  1511. //
  1512. // Retrieve our configuration info from the registry
  1513. //
  1514. dwDataSize = sizeof(iNumLines);
  1515. iNumLines = 0;
  1516. RegQueryValueEx(
  1517. hAtspKey,
  1518. gszNumLines,
  1519. 0,
  1520. &dwDataType,
  1521. (LPBYTE) &iNumLines,
  1522. &dwDataSize
  1523. );
  1524. SendDlgItemMessage(
  1525. hwnd,
  1526. IDC_NAME,
  1527. EM_LIMITTEXT,
  1528. MAX_DEV_NAME_LENGTH,
  1529. 0
  1530. );
  1531. SendDlgItemMessage(
  1532. hwnd,
  1533. IDC_COMMANDS,
  1534. EM_LIMITTEXT,
  1535. MAX_DEV_NAME_LENGTH,
  1536. 0
  1537. );
  1538. pBuf = DrvAlloc (256);
  1539. for (i = 0; i < iNumLines; i++)
  1540. {
  1541. char *p, *p2, szLineN[8];
  1542. PDRVLINECONFIG pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG));
  1543. LONG lResult;
  1544. wsprintf (szLineN, "Line%d", i);
  1545. dwDataSize = 256;
  1546. lResult = RegQueryValueEx(
  1547. hAtspKey,
  1548. szLineN,
  1549. 0,
  1550. &dwDataType,
  1551. (LPBYTE) pBuf,
  1552. &dwDataSize
  1553. );
  1554. //
  1555. // If there was a problem, use the default config
  1556. //
  1557. if (0 != lResult)
  1558. {
  1559. lstrcpy (pBuf, gszDefLineConfigParams);
  1560. }
  1561. for (p = pBuf; *p != ','; p++);
  1562. *p = 0;
  1563. SendDlgItemMessage(
  1564. hwnd,
  1565. IDC_DEVICES,
  1566. LB_ADDSTRING,
  1567. 0,
  1568. (LPARAM) pBuf
  1569. );
  1570. SendDlgItemMessage(
  1571. hwnd,
  1572. IDC_DEVICES,
  1573. LB_SETITEMDATA,
  1574. i,
  1575. (LPARAM) pLineConfig
  1576. );
  1577. p++;
  1578. for (p2 = p; *p2 != ','; p2++);
  1579. *p2 = 0;
  1580. lstrcpy (pLineConfig->szPort, p);
  1581. p = p2 + 1;
  1582. lstrcpy (pLineConfig->szCommands, p);
  1583. }
  1584. DrvFree (pBuf);
  1585. //
  1586. // Fill up the various controls with configuration options
  1587. //
  1588. {
  1589. static char *aszPorts[] = { "COM1","COM2","COM3",NULL };
  1590. for (i = 0; aszPorts[i]; i++)
  1591. {
  1592. SendDlgItemMessage(
  1593. hwnd,
  1594. IDC_PORT,
  1595. LB_ADDSTRING,
  1596. 0,
  1597. (LPARAM) aszPorts[i]
  1598. );
  1599. }
  1600. }
  1601. if (iNumLines == 0)
  1602. {
  1603. EnableChildren (hwnd, FALSE);
  1604. }
  1605. else
  1606. {
  1607. SelectDevice (hwnd, 0);
  1608. }
  1609. break;
  1610. }
  1611. case WM_COMMAND:
  1612. {
  1613. LRESULT lSelection;
  1614. PDRVLINECONFIG pLineConfig;
  1615. lSelection = SendDlgItemMessage(
  1616. hwnd,
  1617. IDC_DEVICES,
  1618. LB_GETCURSEL,
  1619. 0,
  1620. 0
  1621. );
  1622. pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage(
  1623. hwnd,
  1624. IDC_DEVICES,
  1625. LB_GETITEMDATA,
  1626. (WPARAM) lSelection,
  1627. 0
  1628. );
  1629. switch (LOWORD((DWORD)wParam))
  1630. {
  1631. case IDC_DEVICES:
  1632. if (HIWORD(wParam) == LBN_SELCHANGE)
  1633. {
  1634. char buf[MAX_DEV_NAME_LENGTH + 1];
  1635. SendDlgItemMessage(
  1636. hwnd,
  1637. IDC_DEVICES,
  1638. LB_GETTEXT,
  1639. lSelection,
  1640. (LPARAM) buf
  1641. );
  1642. SetDlgItemText (hwnd, IDC_NAME, buf);
  1643. SendDlgItemMessage(
  1644. hwnd,
  1645. IDC_PORT,
  1646. LB_SELECTSTRING,
  1647. (WPARAM) -1,
  1648. (LPARAM) pLineConfig->szPort
  1649. );
  1650. SetDlgItemText (hwnd, IDC_COMMANDS, pLineConfig->szCommands);
  1651. }
  1652. break;
  1653. case IDC_NAME:
  1654. if ((HIWORD(wParam) == EN_CHANGE) && (lSelection != LB_ERR))
  1655. {
  1656. char buf[MAX_DEV_NAME_LENGTH + 1];
  1657. GetDlgItemText (hwnd, IDC_NAME, buf, MAX_DEV_NAME_LENGTH);
  1658. SendDlgItemMessage(
  1659. hwnd,
  1660. IDC_DEVICES,
  1661. LB_DELETESTRING,
  1662. lSelection,
  1663. 0
  1664. );
  1665. SendDlgItemMessage(
  1666. hwnd,
  1667. IDC_DEVICES,
  1668. LB_INSERTSTRING,
  1669. lSelection,
  1670. (LPARAM) buf
  1671. );
  1672. SendDlgItemMessage(
  1673. hwnd,
  1674. IDC_DEVICES,
  1675. LB_SETCURSEL,
  1676. lSelection,
  1677. 0
  1678. );
  1679. SendDlgItemMessage(
  1680. hwnd,
  1681. IDC_DEVICES,
  1682. LB_SETITEMDATA,
  1683. lSelection,
  1684. (LPARAM) pLineConfig
  1685. );
  1686. }
  1687. break;
  1688. case IDC_PORT:
  1689. if (HIWORD(wParam) == LBN_SELCHANGE)
  1690. {
  1691. lSelection = SendDlgItemMessage(
  1692. hwnd,
  1693. IDC_PORT,
  1694. LB_GETCURSEL,
  1695. 0,
  1696. 0
  1697. );
  1698. SendDlgItemMessage(
  1699. hwnd,
  1700. IDC_PORT,
  1701. LB_GETTEXT,
  1702. lSelection,
  1703. (LPARAM) pLineConfig->szPort
  1704. );
  1705. }
  1706. break;
  1707. case IDC_COMMANDS:
  1708. if ((HIWORD(wParam) == EN_CHANGE) && (lSelection != LB_ERR))
  1709. {
  1710. GetDlgItemText(
  1711. hwnd,
  1712. IDC_COMMANDS,
  1713. pLineConfig->szCommands,
  1714. 63
  1715. );
  1716. }
  1717. break;
  1718. case IDC_ADD:
  1719. {
  1720. LRESULT lNumLines, l = 2;
  1721. char szLineName[32];
  1722. PDRVLINECONFIG pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG));
  1723. lNumLines = SendDlgItemMessage(
  1724. hwnd,
  1725. IDC_DEVICES,
  1726. LB_GETCOUNT,
  1727. 0,
  1728. 0
  1729. );
  1730. lstrcpy (pLineConfig->szPort, "COM1");
  1731. lstrcpy (szLineName, "my new line");
  1732. find_unique_line_name:
  1733. if (SendDlgItemMessage(
  1734. hwnd,
  1735. IDC_DEVICES,
  1736. LB_FINDSTRING,
  1737. (WPARAM) -1,
  1738. (LPARAM) szLineName
  1739. ) != LB_ERR)
  1740. {
  1741. wsprintf (szLineName, "my new line%d", l++);
  1742. goto find_unique_line_name;
  1743. }
  1744. SendDlgItemMessage(
  1745. hwnd,
  1746. IDC_DEVICES,
  1747. LB_ADDSTRING,
  1748. 0,
  1749. (LPARAM) szLineName
  1750. );
  1751. SendDlgItemMessage(
  1752. hwnd,
  1753. IDC_DEVICES,
  1754. LB_SETITEMDATA,
  1755. lNumLines,
  1756. (LPARAM) pLineConfig
  1757. );
  1758. EnableChildren (hwnd, TRUE);
  1759. SelectDevice (hwnd, lNumLines);
  1760. SetFocus (GetDlgItem (hwnd, IDC_NAME));
  1761. SendDlgItemMessage(
  1762. hwnd,
  1763. IDC_NAME,
  1764. EM_SETSEL,
  1765. 0,
  1766. (LPARAM) -1
  1767. );
  1768. break;
  1769. }
  1770. case IDC_REMOVE:
  1771. {
  1772. LRESULT lNumLines;
  1773. DrvFree (pLineConfig);
  1774. lNumLines = SendDlgItemMessage(
  1775. hwnd,
  1776. IDC_DEVICES,
  1777. LB_DELETESTRING,
  1778. lSelection,
  1779. 0
  1780. );
  1781. if (lNumLines == 0)
  1782. {
  1783. SetDlgItemText (hwnd, IDC_NAME, "");
  1784. SetDlgItemText (hwnd, IDC_COMMANDS, "");
  1785. EnableChildren (hwnd, FALSE);
  1786. }
  1787. else
  1788. {
  1789. SelectDevice (hwnd, 0);
  1790. }
  1791. break;
  1792. }
  1793. case IDOK:
  1794. {
  1795. char *pBuf;
  1796. LRESULT l, lNumLines;
  1797. //
  1798. // Update the num lines & num phones values
  1799. //
  1800. pBuf = DrvAlloc (256);
  1801. lNumLines = SendDlgItemMessage(
  1802. hwnd,
  1803. IDC_DEVICES,
  1804. LB_GETCOUNT,
  1805. 0,
  1806. 0
  1807. );
  1808. RegSetValueEx(
  1809. hAtspKey,
  1810. gszNumLines,
  1811. 0,
  1812. REG_DWORD,
  1813. (LPBYTE) &lNumLines,
  1814. sizeof(DWORD)
  1815. );
  1816. //
  1817. // For each installed device save it's config info
  1818. //
  1819. for (l = 0; l < lNumLines; l++)
  1820. {
  1821. char szLineN[8];
  1822. PDRVLINECONFIG pLineConfig;
  1823. SendDlgItemMessage(
  1824. hwnd,
  1825. IDC_DEVICES,
  1826. LB_GETTEXT,
  1827. l,
  1828. (LPARAM) pBuf
  1829. );
  1830. pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage(
  1831. hwnd,
  1832. IDC_DEVICES,
  1833. LB_GETITEMDATA,
  1834. l,
  1835. 0
  1836. );
  1837. wsprintf(
  1838. pBuf + strlen (pBuf),
  1839. ",%s,%s",
  1840. pLineConfig->szPort,
  1841. pLineConfig->szCommands
  1842. );
  1843. wsprintf (szLineN, "Line%d", l);
  1844. RegSetValueEx(
  1845. hAtspKey,
  1846. szLineN,
  1847. 0,
  1848. REG_SZ,
  1849. (LPBYTE) pBuf,
  1850. lstrlen (pBuf) + 1
  1851. );
  1852. DrvFree (pLineConfig);
  1853. }
  1854. DrvFree (pBuf);
  1855. // fall thru to EndDialog...
  1856. }
  1857. case IDCANCEL:
  1858. RegCloseKey (hAtspKey);
  1859. EndDialog (hwnd, 0);
  1860. break;
  1861. } // switch (LOWORD((DWORD)wParam))
  1862. break;
  1863. }
  1864. } // switch (msg)
  1865. return FALSE;
  1866. }
  1867. LPVOID
  1868. PASCAL
  1869. DrvAlloc(
  1870. DWORD dwSize
  1871. )
  1872. {
  1873. return (LocalAlloc (LPTR, dwSize));
  1874. }
  1875. VOID
  1876. PASCAL
  1877. DrvFree(
  1878. LPVOID lp
  1879. )
  1880. {
  1881. LocalFree (lp);
  1882. }
  1883. void
  1884. PASCAL
  1885. SetCallState(
  1886. PDRVLINE pLine,
  1887. DWORD dwCallState,
  1888. DWORD dwCallStateMode
  1889. )
  1890. {
  1891. if (dwCallState != pLine->dwCallState)
  1892. {
  1893. pLine->dwCallState = dwCallState;
  1894. pLine->dwCallStateMode = dwCallStateMode;
  1895. (*pLine->pfnEventProc)(
  1896. pLine->htLine,
  1897. pLine->htCall,
  1898. LINE_CALLSTATE,
  1899. dwCallState,
  1900. dwCallStateMode,
  1901. pLine->dwMediaMode
  1902. );
  1903. }
  1904. }
  1905. #if DBG
  1906. void
  1907. PASCAL
  1908. Prolog(
  1909. PFUNC_INFO pInfo
  1910. )
  1911. {
  1912. DWORD i;
  1913. DBGOUT((3, "%s: enter", pInfo->lpszFuncName));
  1914. for (i = 0; i < pInfo->dwNumParams; i++)
  1915. {
  1916. if (pInfo->aParams[i].dwVal &&
  1917. pInfo->aParams[i].lpszVal[3] == 'z') // lpszVal = "lpsz..."
  1918. {
  1919. DBGOUT((
  1920. 3,
  1921. "%s%s=x%lx, '%s'",
  1922. gszTab,
  1923. pInfo->aParams[i].lpszVal,
  1924. pInfo->aParams[i].dwVal,
  1925. pInfo->aParams[i].dwVal
  1926. ));
  1927. }
  1928. else
  1929. {
  1930. DBGOUT((
  1931. 3,
  1932. "%s%s=x%lx",
  1933. gszTab,
  1934. pInfo->aParams[i].lpszVal,
  1935. pInfo->aParams[i].dwVal
  1936. ));
  1937. }
  1938. }
  1939. }
  1940. LONG
  1941. PASCAL
  1942. Epilog(
  1943. PFUNC_INFO pInfo,
  1944. LONG lResult
  1945. )
  1946. {
  1947. DBGOUT((3, "%s: returning x%x", pInfo->lpszFuncName, lResult));
  1948. return lResult;
  1949. }
  1950. void
  1951. CDECL
  1952. DebugOutput(
  1953. DWORD dwDbgLevel,
  1954. LPCSTR lpszFormat,
  1955. ...
  1956. )
  1957. {
  1958. if (dwDbgLevel <= gdwDebugLevel)
  1959. {
  1960. char buf[128] = "ATSP32: ";
  1961. va_list ap;
  1962. va_start(ap, lpszFormat);
  1963. wvsprintf (&buf[8], lpszFormat, ap);
  1964. lstrcat (buf, "\n");
  1965. OutputDebugString (buf);
  1966. va_end(ap);
  1967. }
  1968. }
  1969. #endif
  1970. LONG
  1971. PASCAL
  1972. ProviderInstall(
  1973. char *pszProviderName,
  1974. BOOL bNoMultipleInstance
  1975. )
  1976. {
  1977. LONG lResult;
  1978. //
  1979. // If only one installation instance of this provider is
  1980. // allowed then we want to check the provider list to see
  1981. // if the provider is already installed
  1982. //
  1983. if (bNoMultipleInstance)
  1984. {
  1985. LONG (WINAPI *pfnGetProviderList)();
  1986. DWORD dwTotalSize, i;
  1987. HINSTANCE hTapi32;
  1988. LPLINEPROVIDERLIST pProviderList;
  1989. LPLINEPROVIDERENTRY pProviderEntry;
  1990. //
  1991. // Load Tapi32.dll & get a pointer to the lineGetProviderList
  1992. // func. We don't want to statically link because this module
  1993. // plays the part of both core SP & UI DLL, and we don't want
  1994. // to incur the performance hit of automatically loading
  1995. // Tapi32.dll when running as a core SP within Tapisrv.exe's
  1996. // context.
  1997. //
  1998. if (!(hTapi32 = LoadLibrary ("tapi32.dll")))
  1999. {
  2000. DBGOUT((
  2001. 1,
  2002. "LoadLibrary(tapi32.dll) failed, err=%d",
  2003. GetLastError()
  2004. ));
  2005. lResult = LINEERR_OPERATIONFAILED;
  2006. goto ProviderInstall_return;
  2007. }
  2008. if (!((FARPROC) pfnGetProviderList = GetProcAddress(
  2009. hTapi32,
  2010. (LPCSTR) "lineGetProviderList"
  2011. )))
  2012. {
  2013. DBGOUT((
  2014. 1,
  2015. "GetProcAddr(lineGetProviderList) failed, err=%d",
  2016. GetLastError()
  2017. ));
  2018. lResult = LINEERR_OPERATIONFAILED;
  2019. goto ProviderInstall_unloadTapi32;
  2020. }
  2021. //
  2022. // Loop until we get the full provider list
  2023. //
  2024. dwTotalSize = sizeof (LINEPROVIDERLIST);
  2025. goto ProviderInstall_allocProviderList;
  2026. ProviderInstall_getProviderList:
  2027. if ((lResult = (*pfnGetProviderList)(0x00020000, pProviderList)) != 0)
  2028. {
  2029. goto ProviderInstall_freeProviderList;
  2030. }
  2031. if (pProviderList->dwNeededSize > pProviderList->dwTotalSize)
  2032. {
  2033. dwTotalSize = pProviderList->dwNeededSize;
  2034. LocalFree (pProviderList);
  2035. ProviderInstall_allocProviderList:
  2036. if (!(pProviderList = LocalAlloc (LPTR, dwTotalSize)))
  2037. {
  2038. lResult = LINEERR_NOMEM;
  2039. goto ProviderInstall_unloadTapi32;
  2040. }
  2041. pProviderList->dwTotalSize = dwTotalSize;
  2042. goto ProviderInstall_getProviderList;
  2043. }
  2044. //
  2045. // Inspect the provider list entries to see if this provider
  2046. // is already installed
  2047. //
  2048. pProviderEntry = (LPLINEPROVIDERENTRY) (((LPBYTE) pProviderList) +
  2049. pProviderList->dwProviderListOffset);
  2050. for (i = 0; i < pProviderList->dwNumProviders; i++)
  2051. {
  2052. char *pszInstalledProviderName = ((char *) pProviderList) +
  2053. pProviderEntry->dwProviderFilenameOffset,
  2054. *p;
  2055. //
  2056. // Make sure pszInstalledProviderName points at <filename>
  2057. // and not <path>\filename by walking backeards thru the
  2058. // string searching for last '\\'
  2059. //
  2060. p = pszInstalledProviderName +
  2061. lstrlen (pszInstalledProviderName) - 1;
  2062. for (; *p != '\\' && p != pszInstalledProviderName; p--);
  2063. pszInstalledProviderName =
  2064. (p == pszInstalledProviderName ? p : p + 1);
  2065. if (lstrcmpiA (pszInstalledProviderName, pszProviderName) == 0)
  2066. {
  2067. lResult = LINEERR_NOMULTIPLEINSTANCE;
  2068. goto ProviderInstall_freeProviderList;
  2069. }
  2070. pProviderEntry++;
  2071. }
  2072. //
  2073. // If here then the provider isn't currently installed,
  2074. // so do whatever configuration stuff is necessary and
  2075. // indicate SUCCESS
  2076. //
  2077. lResult = 0;
  2078. ProviderInstall_freeProviderList:
  2079. LocalFree (pProviderList);
  2080. ProviderInstall_unloadTapi32:
  2081. FreeLibrary (hTapi32);
  2082. }
  2083. else
  2084. {
  2085. //
  2086. // Do whatever configuration stuff is necessary and return SUCCESS
  2087. //
  2088. lResult = 0;
  2089. }
  2090. ProviderInstall_return:
  2091. return lResult;
  2092. }
  2093. void
  2094. PASCAL
  2095. DropActiveCall(
  2096. PDRVLINE pLine
  2097. )
  2098. {
  2099. if (pLine->hComm)
  2100. {
  2101. DWORD dwNumBytes, dwError;
  2102. OVERLAPPED overlapped;
  2103. pLine->bDropInProgress = TRUE;
  2104. SetEvent (pLine->Overlapped.hEvent);
  2105. ZeroMemory (&overlapped, sizeof (OVERLAPPED));
  2106. overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  2107. if (pLine->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE)
  2108. {
  2109. if (!WriteFile(
  2110. pLine->hComm,
  2111. "+++\r", 4,
  2112. &dwNumBytes,
  2113. &overlapped
  2114. ))
  2115. {
  2116. if ((dwError = GetLastError()) == ERROR_IO_PENDING)
  2117. {
  2118. GetOverlappedResult(
  2119. pLine->hComm,
  2120. &overlapped,
  2121. &dwNumBytes,
  2122. TRUE
  2123. );
  2124. ResetEvent (overlapped.hEvent);
  2125. }
  2126. else
  2127. {
  2128. }
  2129. }
  2130. }
  2131. if (!WriteFile (pLine->hComm, "ATH\r", 4, &dwNumBytes, &overlapped))
  2132. {
  2133. if ((dwError = GetLastError()) == ERROR_IO_PENDING)
  2134. {
  2135. GetOverlappedResult(
  2136. pLine->hComm,
  2137. &overlapped,
  2138. &dwNumBytes,
  2139. TRUE
  2140. );
  2141. }
  2142. else
  2143. {
  2144. }
  2145. }
  2146. CloseHandle (overlapped.hEvent);
  2147. CloseHandle (pLine->hComm);
  2148. pLine->hComm = NULL;
  2149. }
  2150. }