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.

1917 lines
44 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. line.c
  5. Abstract:
  6. TAPI Service Provider functions related to manipulating lines.
  7. TSPI_lineClose
  8. TSPI_lineGetDevCaps
  9. TSPI_lineGetLineDevStatus
  10. TSPI_lineGetNumAddressIDs
  11. TSPI_lineOpen
  12. TSPI_lineSetLineDevStatus
  13. Environment:
  14. User Mode - Win32
  15. --*/
  16. ///////////////////////////////////////////////////////////////////////////////
  17. // //
  18. // Include files //
  19. // //
  20. ///////////////////////////////////////////////////////////////////////////////
  21. #include "globals.h"
  22. #include "provider.h"
  23. #include "callback.h"
  24. #include "registry.h"
  25. #include "version.h"
  26. #include "line.h"
  27. #include "call.h"
  28. ///////////////////////////////////////////////////////////////////////////////
  29. // //
  30. // Global variables //
  31. // //
  32. ///////////////////////////////////////////////////////////////////////////////
  33. PH323_LINE_TABLE g_pLineTable = NULL;
  34. DWORD g_dwLineDeviceUniqueID = 0;
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // //
  37. // Private procedures //
  38. // //
  39. ///////////////////////////////////////////////////////////////////////////////
  40. BOOL
  41. H323ResetLine(
  42. PH323_LINE pLine
  43. )
  44. /*++
  45. Routine Description:
  46. Resets line object to original state for re-use.
  47. Arguments:
  48. pLine - Pointer to line object to reset.
  49. Return Values:
  50. Returns true if successful.
  51. --*/
  52. {
  53. // reset state of line object
  54. pLine->nState = H323_LINESTATE_ALLOCATED;
  55. // line not marked for deletion
  56. pLine->fIsMarkedForDeletion = FALSE;
  57. // reset tapi handles
  58. pLine->hdLine = (HDRVLINE)NULL;
  59. pLine->htLine = (HTAPILINE)NULL;
  60. pLine->dwDeviceID = UNINITIALIZED;
  61. // reset tapi info
  62. pLine->dwTSPIVersion = 0;
  63. pLine->dwMediaModes = 0;
  64. // reset bogus handle count
  65. pLine->dwNextMSPHandle = 0;
  66. // uninitialize listen handle
  67. pLine->hccListen = UNINITIALIZED;
  68. // reset line name
  69. pLine->wszAddr[0] = UNICODE_NULL;
  70. // success
  71. return TRUE;
  72. }
  73. BOOL
  74. H323AllocLine(
  75. PH323_LINE * ppLine
  76. )
  77. /*++
  78. Routine Description:
  79. Allocates line device.
  80. Arguments:
  81. ppLine - Pointer to DWORD-sized value which service provider must
  82. write the newly allocated line.
  83. Return Values:
  84. Returns true if successful.
  85. --*/
  86. {
  87. HRESULT hr;
  88. PH323_LINE pLine;
  89. // allocate object from heap
  90. pLine = H323HeapAlloc(sizeof(H323_LINE));
  91. // validate pointer
  92. if (pLine == NULL) {
  93. H323DBG((
  94. DEBUG_LEVEL_ERROR,
  95. "could not allocate line object.\n"
  96. ));
  97. // failure
  98. return FALSE;
  99. }
  100. __try {
  101. // initialize lock (and allocate event immediately)
  102. InitializeCriticalSectionAndSpinCount(&pLine->Lock,H323_SPIN_COUNT);
  103. } __except ((GetExceptionCode() == STATUS_NO_MEMORY)
  104. ? EXCEPTION_EXECUTE_HANDLER
  105. : EXCEPTION_CONTINUE_SEARCH
  106. ) {
  107. // release object
  108. H323HeapFree(pLine);
  109. // failure
  110. return FALSE;
  111. }
  112. // allocate call table
  113. if (!H323AllocCallTable(&pLine->pCallTable)) {
  114. // release critical section
  115. DeleteCriticalSection(&pLine->Lock);
  116. // release object
  117. H323HeapFree(pLine);
  118. // failure
  119. return FALSE;
  120. }
  121. // initialize rtp/rtcp base port
  122. pLine->dwNextPort = H323_RTPBASEPORT;
  123. // reset line
  124. H323ResetLine(pLine);
  125. // transfer
  126. *ppLine = pLine;
  127. // success
  128. return TRUE;
  129. }
  130. BOOL
  131. H323FreeLine(
  132. PH323_LINE pLine
  133. )
  134. /*++
  135. Routine Description:
  136. Releases line device.
  137. Arguments:
  138. pLine - Pointer to line device to release.
  139. Return Values:
  140. Returns true if successful.
  141. --*/
  142. {
  143. // validate pointer
  144. if (pLine != NULL) {
  145. // release memory for call table
  146. H323FreeCallTable(pLine->pCallTable);
  147. // release critical section
  148. DeleteCriticalSection(&pLine->Lock);
  149. // release line
  150. H323HeapFree(pLine);
  151. }
  152. H323DBG((
  153. DEBUG_LEVEL_VERBOSE,
  154. "line 0x%08lx released.\n",
  155. pLine
  156. ));
  157. // success
  158. return TRUE;
  159. }
  160. BOOL
  161. H323OpenLine(
  162. PH323_LINE pLine,
  163. HTAPILINE htLine,
  164. DWORD dwTSPIVersion
  165. )
  166. /*++
  167. Routine Description:
  168. Initiate activities on line device and allocate resources.
  169. Arguments:
  170. pLine - Pointer to line device to open.
  171. htLine - TAPI's handle describing line device to open.
  172. dwTSPIVersion - The TSPI version negotiated through
  173. TSPI_lineNegotiateTSPIVersion under which the Service Provider is
  174. willing to operate.
  175. Return Values:
  176. Returns true if successful.
  177. --*/
  178. {
  179. H323DBG((
  180. DEBUG_LEVEL_TRACE,
  181. "line %d opening.\n",
  182. pLine->dwDeviceID
  183. ));
  184. // start listen if necessary
  185. if (H323IsMediaDetectionEnabled(pLine) &&
  186. !H323StartListening(pLine)) {
  187. // failure
  188. return FALSE;
  189. }
  190. // save line variables now
  191. pLine->htLine = htLine;
  192. pLine->dwTSPIVersion = dwTSPIVersion;
  193. // change line device state to opened
  194. pLine->nState = H323_LINESTATE_OPENED;
  195. // success
  196. return TRUE;
  197. }
  198. BOOL
  199. H323CloseLine(
  200. PH323_LINE pLine
  201. )
  202. /*++
  203. Routine Description:
  204. Terminate activities on line device.
  205. Arguments:
  206. pLine - Pointer to line device to close.
  207. Return Values:
  208. Returns true if successful.
  209. --*/
  210. {
  211. H323DBG((
  212. DEBUG_LEVEL_TRACE,
  213. "line %d %s.\n",
  214. pLine->dwDeviceID,
  215. pLine->fIsMarkedForDeletion
  216. ? "closing and being removed"
  217. : "closing"
  218. ));
  219. // see if we are listening
  220. if (H323IsListening(pLine)) {
  221. // stop listening first
  222. H323StopListening(pLine);
  223. }
  224. // change line device state to closing
  225. pLine->nState = H323_LINESTATE_CLOSING;
  226. // close all calls now in table
  227. H323CloseCallTable(pLine->pCallTable);
  228. // delete line if marked
  229. if (pLine->fIsMarkedForDeletion) {
  230. // remove line device from table
  231. H323FreeLineFromTable(pLine, g_pLineTable);
  232. } else {
  233. // reset variables
  234. pLine->htLine = (HTAPILINE)NULL;
  235. pLine->dwTSPIVersion = 0;
  236. pLine->dwMediaModes = 0;
  237. // change line device state to closed
  238. pLine->nState = H323_LINESTATE_CLOSED;
  239. }
  240. // success
  241. return TRUE;
  242. }
  243. BOOL
  244. H323InitializeLine(
  245. PH323_LINE pLine,
  246. DWORD dwDeviceID
  247. )
  248. /*++
  249. Routine Description:
  250. Updates line device based on changes in registry.
  251. Arguments:
  252. pLine - Pointer to line device to update.
  253. dwDeviceID - Device ID specified in TSPI_providerInit.
  254. Return Values:
  255. Returns true if successful.
  256. --*/
  257. {
  258. DWORD dwSize = sizeof(pLine->wszAddr);
  259. // save line device id
  260. pLine->dwDeviceID = dwDeviceID;
  261. // create displayable address
  262. GetComputerNameW(pLine->wszAddr, &dwSize);
  263. H323DBG((
  264. DEBUG_LEVEL_TRACE,
  265. "line %d initialized (addr=%S).\n",
  266. pLine->dwDeviceID,
  267. pLine->wszAddr
  268. ));
  269. // change line device state to closed
  270. pLine->nState = H323_LINESTATE_CLOSED;
  271. // success
  272. return TRUE;
  273. }
  274. ///////////////////////////////////////////////////////////////////////////////
  275. // //
  276. // Public procedures //
  277. // //
  278. ///////////////////////////////////////////////////////////////////////////////
  279. BOOL
  280. H323GetLineAndLock(
  281. PH323_LINE * ppLine,
  282. HDRVLINE hdLine
  283. )
  284. /*++
  285. Routine Description:
  286. Retrieves pointer to line device given line handle.
  287. Arguments:
  288. ppLine - Specifies a pointer to a DWORD-sized memory location
  289. into which the service provider must write the line device pointer
  290. associated with the given line handle.
  291. hdLine - Specifies the Service Provider's opaque handle to the line.
  292. Return Values:
  293. Returns true if successful.
  294. --*/
  295. {
  296. DWORD i;
  297. PH323_LINE pLine = NULL;
  298. // lock provider
  299. H323LockProvider();
  300. // retrieve line table index
  301. i = H323GetLineTableIndex(PtrToUlong(hdLine));
  302. // validate line table index
  303. if (i >= g_pLineTable->dwNumSlots) {
  304. H323DBG((
  305. DEBUG_LEVEL_ERROR,
  306. "line handle 0x%08lx invalid.\n",
  307. PtrToUlong(hdLine)
  308. ));
  309. // unlock provider
  310. H323UnlockProvider();
  311. // failure
  312. return FALSE;
  313. }
  314. // retrieve line pointer from table
  315. pLine = g_pLineTable->pLines[i];
  316. // validate call information
  317. if (!H323IsLineEqual(pLine,hdLine)) {
  318. H323DBG((
  319. DEBUG_LEVEL_ERROR,
  320. "line handle 0x%08lx invalid.\n",
  321. PtrToUlong(hdLine)
  322. ));
  323. // unlock provider
  324. H323UnlockProvider();
  325. // failure
  326. return FALSE;
  327. }
  328. // lock line device
  329. H323LockLine(pLine);
  330. // unlock provider
  331. H323UnlockProvider();
  332. // transfer
  333. *ppLine = pLine;
  334. // success
  335. return TRUE;
  336. }
  337. BOOL
  338. H323GetLineFromIDAndLock(
  339. PH323_LINE * ppLine,
  340. DWORD dwDeviceID
  341. )
  342. /*++
  343. Routine Description:
  344. Retrieves pointer to line device given device id.
  345. Arguments:
  346. ppLine - Specifies a pointer to a DWORD-sized memory location
  347. into which the service provider must write the line device pointer
  348. associated with the given device ID.
  349. dwDeviceID - Identifies the line device.
  350. Return Values:
  351. Returns true if successful.
  352. --*/
  353. {
  354. DWORD i;
  355. // lock provider
  356. H323LockProvider();
  357. // loop through each objectin table
  358. for (i = 0; i < g_pLineTable->dwNumSlots; i++) {
  359. // validate object is allocated
  360. if (H323IsLineAllocated(g_pLineTable->pLines[i])) {
  361. // lock line device
  362. H323LockLine(g_pLineTable->pLines[i]);
  363. // compare stored device id with the one specified
  364. if (H323IsLineInUse(g_pLineTable->pLines[i]) &&
  365. (g_pLineTable->pLines[i]->dwDeviceID == dwDeviceID)) {
  366. // transfer line device pointer
  367. *ppLine = g_pLineTable->pLines[i];
  368. // unlock provider
  369. H323UnlockProvider();
  370. // success
  371. return TRUE;
  372. }
  373. // release line device
  374. H323UnlockLine(g_pLineTable->pLines[i]);
  375. }
  376. }
  377. // unlock provider
  378. H323UnlockProvider();
  379. // initialize
  380. *ppLine = NULL;
  381. // failure
  382. return FALSE;
  383. }
  384. BOOL
  385. H323CallListen(
  386. PH323_LINE pLine
  387. )
  388. /*++
  389. Routine Description:
  390. Starts listening for calls on given line device.
  391. Arguments:
  392. pLine - Pointer to line device to start listening.
  393. Return Values:
  394. Returns true if successful.
  395. --*/
  396. {
  397. HRESULT hr;
  398. CC_ADDR ListenAddr;
  399. // construct listen address
  400. ListenAddr.nAddrType = CC_IP_BINARY;
  401. ListenAddr.Addr.IP_Binary.dwAddr = INADDR_ANY;
  402. ListenAddr.Addr.IP_Binary.wPort =
  403. LOWORD(g_RegistrySettings.dwQ931CallSignallingPort);
  404. ListenAddr.bMulticast = FALSE;
  405. // start listening
  406. hr = CC_CallListen(
  407. &pLine->hccListen, // phListen
  408. &ListenAddr, // pListenAddr
  409. NULL, // pLocalAliasNames
  410. PtrToUlong(pLine->hdLine), // dwListenToken
  411. H323ListenCallback // ListenCallback
  412. );
  413. // validate status
  414. if (hr != S_OK) {
  415. H323DBG((
  416. DEBUG_LEVEL_ERROR,
  417. "error 0x%08lx calling CC_CallListen.\n", hr
  418. ));
  419. // re-initialize call listen handle
  420. pLine->hccListen = UNINITIALIZED;
  421. // failure
  422. return FALSE;
  423. }
  424. H323DBG((
  425. DEBUG_LEVEL_VERBOSE,
  426. "line %d listening for incoming calls.\n",
  427. pLine->dwDeviceID
  428. ));
  429. // success
  430. return TRUE;
  431. }
  432. BOOL
  433. H323StartListening(
  434. PH323_LINE pLine
  435. )
  436. /*++
  437. Routine Description:
  438. Starts listening for calls on given line device.
  439. Arguments:
  440. pLine - Pointer to line device to start listening.
  441. Return Values:
  442. Returns true if successful.
  443. --*/
  444. {
  445. // attempt to post call listen message
  446. if (!H323PostCallListenMessage(pLine->hdLine)) {
  447. H323DBG((
  448. DEBUG_LEVEL_ERROR,
  449. "error 0x%08lx posting call listen.\n",
  450. GetLastError()
  451. ));
  452. // failure
  453. return FALSE;
  454. }
  455. // change state to listening
  456. pLine->nState = H323_LINESTATE_LISTENING;
  457. // success
  458. return TRUE;
  459. }
  460. BOOL
  461. H323StopListening(
  462. PH323_LINE pLine
  463. )
  464. /*++
  465. Routine Description:
  466. Stops listening for calls on given line device.
  467. Arguments:
  468. pLine - Pointer to line device to stop listening.
  469. Return Values:
  470. Returns true if successful.
  471. --*/
  472. {
  473. HRESULT hr;
  474. // stop listening
  475. hr = CC_CancelListen(pLine->hccListen);
  476. // validate status
  477. if (hr != S_OK) {
  478. H323DBG((
  479. DEBUG_LEVEL_ERROR,
  480. "error 0x%08lx calling CC_CancelListen.\n", hr
  481. ));
  482. //
  483. // Unable to cancel listen on line
  484. // device so uninitialize handle and
  485. // continue...
  486. //
  487. }
  488. // change state to opened
  489. pLine->nState = H323_LINESTATE_OPENED;
  490. // uninitialize listen handle
  491. pLine->hccListen = UNINITIALIZED;
  492. H323DBG((
  493. DEBUG_LEVEL_VERBOSE,
  494. "line %d no longer listening for incoming calls.\n",
  495. pLine->dwDeviceID
  496. ));
  497. // success
  498. return TRUE;
  499. }
  500. BOOL
  501. H323AllocLineTable(
  502. PH323_LINE_TABLE * ppLineTable
  503. )
  504. /*++
  505. Routine Description:
  506. Allocates table of line objects.
  507. Arguments:
  508. ppLineTable - Pointer to LPVOID-size memory location in which
  509. service provider will write pointer to line table.
  510. Return Values:
  511. Returns true if successful.
  512. --*/
  513. {
  514. int i;
  515. DWORD dwStatus;
  516. PH323_LINE_TABLE pLineTable;
  517. PH323_LINE pLine;
  518. BOOL fOk = FALSE;
  519. // allocate table from heap
  520. pLineTable = H323HeapAlloc(
  521. sizeof(H323_LINE_TABLE) +
  522. sizeof(PH323_LINE) * H323_DEFLINESPERINST
  523. );
  524. // validate table pointer
  525. if (pLineTable == NULL) {
  526. H323DBG((
  527. DEBUG_LEVEL_ERROR,
  528. "could not allocate line table.\n"
  529. ));
  530. // failure
  531. goto cleanup;
  532. }
  533. // initialize number of slots
  534. pLineTable->dwNumSlots = H323_DEFLINESPERINST;
  535. // allocate line device
  536. if (!H323AllocLineFromTable(&pLine,&pLineTable)) {
  537. H323DBG((
  538. DEBUG_LEVEL_ERROR,
  539. "could not allocate default line.\n"
  540. ));
  541. // failure
  542. goto cleanup;
  543. }
  544. // transfer pointer
  545. *ppLineTable = pLineTable;
  546. // re-initialize
  547. pLineTable = NULL;
  548. // success
  549. fOk = TRUE;
  550. cleanup:
  551. // validate pointer
  552. if (pLineTable != NULL) {
  553. // free new table
  554. H323FreeLineTable(pLineTable);
  555. }
  556. // done...
  557. return fOk;
  558. }
  559. BOOL
  560. H323FreeLineTable(
  561. PH323_LINE_TABLE pLineTable
  562. )
  563. /*++
  564. Routine Description:
  565. Deallocates table of line objects.
  566. Arguments:
  567. pLineTable - Pointer to line table to release.
  568. Return Values:
  569. Returns true if successful.
  570. --*/
  571. {
  572. DWORD i;
  573. // loop through each object in table
  574. for (i = 0; i < pLineTable->dwNumSlots; i++) {
  575. // validate object has been allocated
  576. if (H323IsLineAllocated(pLineTable->pLines[i])) {
  577. // release memory for object
  578. H323FreeLine(pLineTable->pLines[i]);
  579. }
  580. }
  581. // release memory for table
  582. H323HeapFree(pLineTable);
  583. // success
  584. return TRUE;
  585. }
  586. BOOL
  587. H323CloseLineTable(
  588. PH323_LINE_TABLE pLineTable
  589. )
  590. /*++
  591. Routine Description:
  592. Closes table of line objects.
  593. Arguments:
  594. pLineTable - Pointer to table to close.
  595. Return Values:
  596. Returns true if successful.
  597. --*/
  598. {
  599. DWORD i;
  600. // loop through each objectin table
  601. for (i = 0; i < pLineTable->dwNumSlots; i++) {
  602. // validate object is allocated
  603. if (H323IsLineAllocated(pLineTable->pLines[i])) {
  604. // lock line device
  605. H323LockLine(pLineTable->pLines[i]);
  606. // see if line device in use
  607. if (H323IsLineInUse(pLineTable->pLines[i])) {
  608. // close previously opened object
  609. H323CloseLine(pLineTable->pLines[i]);
  610. }
  611. // release line device
  612. H323UnlockLine(pLineTable->pLines[i]);
  613. }
  614. }
  615. // reset table information
  616. pLineTable->dwNumInUse = 0;
  617. pLineTable->dwNextAvailable = 0;
  618. // success
  619. return TRUE;
  620. }
  621. BOOL
  622. H323AllocLineFromTable(
  623. PH323_LINE * ppLine,
  624. PH323_LINE_TABLE * ppLineTable
  625. )
  626. /*++
  627. Routine Description:
  628. Allocates line object in table.
  629. Arguments:
  630. ppLine - Specifies a pointer to a DWORD-sized value in which the
  631. service provider must write the allocated line object.
  632. ppLineTable - Pointer to pointer to line table in which to
  633. allocate line from (expands table if necessary).
  634. Return Values:
  635. Returns true if successful.
  636. --*/
  637. {
  638. DWORD i;
  639. PH323_LINE pLine = NULL;
  640. PH323_LINE_TABLE pLineTable = *ppLineTable;
  641. // retrieve index to next entry
  642. i = pLineTable->dwNextAvailable;
  643. // see if previously allocated entries available
  644. if (pLineTable->dwNumAllocated > pLineTable->dwNumInUse) {
  645. // search table looking for available entry
  646. while (H323IsLineInUse(pLineTable->pLines[i]) ||
  647. !H323IsLineAllocated(pLineTable->pLines[i])) {
  648. // increment index and adjust to wrap
  649. i = H323GetNextIndex(i, pLineTable->dwNumSlots);
  650. }
  651. // retrieve pointer to object
  652. pLine = pLineTable->pLines[i];
  653. // mark entry as waiting for line device id
  654. pLine->nState = H323_LINESTATE_WAITING_FOR_ID;
  655. // initialize call handle with index
  656. pLine->hdLine = H323CreateLineHandle(i);
  657. // temporary device id
  658. pLine->dwDeviceID = PtrToUlong(pLine->hdLine);
  659. // increment number in use
  660. pLineTable->dwNumInUse++;
  661. // adjust next available index
  662. pLineTable->dwNextAvailable =
  663. H323GetNextIndex(i, pLineTable->dwNumSlots);
  664. // transfer pointer
  665. *ppLine = pLine;
  666. // success
  667. return TRUE;
  668. }
  669. // see if table is full and more slots need to be allocated
  670. if (pLineTable->dwNumAllocated == pLineTable->dwNumSlots) {
  671. // attempt to double table
  672. pLineTable = H323HeapReAlloc(
  673. pLineTable,
  674. sizeof(H323_LINE_TABLE) +
  675. pLineTable->dwNumSlots * 2 * sizeof(PH323_LINE)
  676. );
  677. // validate pointer
  678. if (pLineTable == NULL) {
  679. H323DBG((
  680. DEBUG_LEVEL_ERROR,
  681. "could not expand channel table.\n"
  682. ));
  683. // failure
  684. return FALSE;
  685. }
  686. // adjust index into table
  687. i = pLineTable->dwNumSlots;
  688. // adjust number of slots
  689. pLineTable->dwNumSlots *= 2;
  690. // transfer pointer to caller
  691. *ppLineTable = pLineTable;
  692. }
  693. // allocate new object
  694. if (!H323AllocLine(&pLine)) {
  695. // failure
  696. return FALSE;
  697. }
  698. // search table looking for slot with no object allocated
  699. while (H323IsLineAllocated(pLineTable->pLines[i])) {
  700. // increment index and adjust to wrap
  701. i = H323GetNextIndex(i, pLineTable->dwNumSlots);
  702. }
  703. // store pointer to object
  704. pLineTable->pLines[i] = pLine;
  705. // mark entry as being in use
  706. pLine->nState = H323_LINESTATE_CLOSED;
  707. // initialize call handle with index
  708. pLine->hdLine = H323CreateLineHandle(i);
  709. // temporary device id
  710. pLine->dwDeviceID = PtrToUlong(pLine->hdLine);
  711. // increment number in use
  712. pLineTable->dwNumInUse++;
  713. // increment number allocated
  714. pLineTable->dwNumAllocated++;
  715. // adjust next available index
  716. pLineTable->dwNextAvailable =
  717. H323GetNextIndex(i, pLineTable->dwNumSlots);
  718. // transfer pointer
  719. *ppLine = pLine;
  720. // success
  721. return TRUE;
  722. }
  723. BOOL
  724. H323FreeLineFromTable(
  725. PH323_LINE pLine,
  726. PH323_LINE_TABLE pLineTable
  727. )
  728. /*++
  729. Routine Description:
  730. Deallocates line object in table.
  731. Arguments:
  732. pLine - Pointer to object to deallocate.
  733. pLineTable - Pointer to table containing object.
  734. Return Values:
  735. Returns true if successful.
  736. --*/
  737. {
  738. // reset line object
  739. H323ResetLine(pLine);
  740. // decrement entries in use
  741. pLineTable->dwNumInUse--;
  742. // success
  743. return TRUE;
  744. }
  745. BOOL
  746. H323InitializeLineTable(
  747. PH323_LINE_TABLE pLineTable,
  748. DWORD dwLineDeviceIDBase
  749. )
  750. /*++
  751. Routine Description:
  752. Updates line devices based on changes to registry settings.
  753. Arguments:
  754. pLineTable - Pointer to line table to update.
  755. dwLineDeviceIDBase - Device ID specified in TSPI_providerInit.
  756. Return Values:
  757. Returns true if successful.
  758. --*/
  759. {
  760. UINT i;
  761. // loop through line device structures
  762. for (i = 0; i < pLineTable->dwNumSlots; i++) {
  763. // see if line is allocated
  764. if (H323IsLineAllocated(pLineTable->pLines[i])) {
  765. // lock line device
  766. H323LockLine(pLineTable->pLines[i]);
  767. // see if line device is in user
  768. if (H323IsLineInUse(pLineTable->pLines[i])) {
  769. // update settings
  770. H323InitializeLine(
  771. pLineTable->pLines[i],
  772. dwLineDeviceIDBase + g_dwLineDeviceUniqueID++
  773. );
  774. }
  775. // unlock line device
  776. H323UnlockLine(pLineTable->pLines[i]);
  777. }
  778. }
  779. // success
  780. return TRUE;
  781. }
  782. BOOL
  783. H323RemoveLine(
  784. PH323_LINE pLine
  785. )
  786. /*++
  787. Routine Description:
  788. Adds line device to line table.
  789. Arguments:
  790. pLine - Pointer to line device to remove.
  791. Return Values:
  792. Returns true if successful.
  793. --*/
  794. {
  795. // mark line as about to be removed
  796. pLine->fIsMarkedForDeletion = TRUE;
  797. // fire close event
  798. (*g_pfnLineEventProc)(
  799. (HTAPILINE)0, // htLine
  800. (HTAPICALL)0, // htCall
  801. LINE_REMOVE, // dwMsg
  802. pLine->dwDeviceID, // dwParam1
  803. 0, // dwParam2
  804. 0 // dwParam3
  805. );
  806. // see if line closed
  807. if (H323IsLineClosed(pLine)) {
  808. H323DBG((
  809. DEBUG_LEVEL_TRACE,
  810. "line %d being removed.\n",
  811. pLine->dwDeviceID
  812. ));
  813. // remove line device from table
  814. H323FreeLineFromTable(pLine, g_pLineTable);
  815. }
  816. // success
  817. return TRUE;
  818. }
  819. #if defined(DBG) && defined(DEBUG_CRITICAL_SECTIONS)
  820. VOID
  821. H323LockLine(
  822. PH323_LINE pLine
  823. )
  824. /*++
  825. Routine Description:
  826. Locks line device.
  827. Arguments:
  828. pLine - Pointer to line to lock.
  829. Return Values:
  830. None.
  831. --*/
  832. {
  833. H323DBG((
  834. DEBUG_LEVEL_VERBOSE,
  835. "line %d about to be locked.\n",
  836. pLine->dwDeviceID
  837. ));
  838. // lock line device
  839. EnterCriticalSection(&pLine->Lock);
  840. H323DBG((
  841. DEBUG_LEVEL_VERBOSE,
  842. "line %d locked.\n",
  843. pLine->dwDeviceID
  844. ));
  845. }
  846. VOID
  847. H323UnlockLine(
  848. PH323_LINE pLine
  849. )
  850. /*++
  851. Routine Description:
  852. Unlocks line device.
  853. Arguments:
  854. pLine - Pointer to line to unlock.
  855. Return Values:
  856. None.
  857. --*/
  858. {
  859. // unlock line device
  860. LeaveCriticalSection(&pLine->Lock);
  861. H323DBG((
  862. DEBUG_LEVEL_VERBOSE,
  863. "line %d unlocked.\n",
  864. pLine->dwDeviceID
  865. ));
  866. }
  867. #endif // DBG && DEBUG_CRITICAL_SECTIONS
  868. ///////////////////////////////////////////////////////////////////////////////
  869. // //
  870. // TSPI procedures //
  871. // //
  872. ///////////////////////////////////////////////////////////////////////////////
  873. LONG
  874. TSPIAPI
  875. TSPI_lineClose(
  876. HDRVLINE hdLine
  877. )
  878. /*++
  879. Routine Description:
  880. This function closes the specified open line device after completing or
  881. aborting all outstanding calls and asynchronous operations on the device.
  882. The Service Provider has the responsibility to (eventually) report
  883. completion for every operation it decides to execute asynchronously.
  884. If this procedure is called for a line on which there are outstanding
  885. asynchronous operations, the operations should be reported complete with an
  886. appropriate result or error code before this procedure returns. Generally
  887. the TAPI DLL would wait for these to complete in an orderly fashion.
  888. However, the Service Provider should be prepared to handle an early call to
  889. TSPI_lineClose in "abort" or "emergency shutdown" situtations.
  890. A similar requirement exists for active calls on the line. Such calls must
  891. be dropped, with outstanding operations reported complete with appropriate
  892. result or error codes.
  893. After this procedure returns the Service Provider must report no further
  894. events on the line or calls that were on the line. The Service Provider's
  895. opaque handles for the line and calls on the line become "invalid".
  896. The Service Provider must relinquish non-sharable resources it reserves
  897. while the line is open. For example, closing a line accessed through a
  898. comm port and modem should result in closing the comm port, making it once
  899. available for use by other applications.
  900. This function is presumed to complete successfully and synchronously.
  901. Arguments:
  902. hdLine - Specifies the Service Provider's opaque handle to the line to be
  903. closed. After the line has been successfully closed, this handle is
  904. no longer valid.
  905. Return Values:
  906. Returns zero if the function is successful, or a negative error
  907. number if an error has occurred. Possible error returns are:
  908. LINEERR_INVALLINEHANDLE - The specified device handle is invalid.
  909. LINEERR_OPERATIONFAILED - The specified operation failed for unknown
  910. reasons.
  911. --*/
  912. {
  913. PH323_LINE pLine = NULL;
  914. // retrieve line pointer from handle
  915. if (!H323GetLineAndLock(&pLine, hdLine)) {
  916. // invalid line handle
  917. return LINEERR_INVALLINEHANDLE;
  918. }
  919. // attempt to close line device
  920. if (!H323CloseLine(pLine)) {
  921. // release line device
  922. H323UnlockLine(pLine);
  923. // could not close line device
  924. return LINEERR_OPERATIONFAILED;
  925. }
  926. // release line device
  927. H323UnlockLine(pLine);
  928. // success
  929. return NOERROR;
  930. }
  931. LONG
  932. TSPIAPI
  933. TSPI_lineGetDevCaps(
  934. DWORD dwDeviceID,
  935. DWORD dwTSPIVersion,
  936. DWORD dwExtVersion,
  937. LPLINEDEVCAPS pLineDevCaps
  938. )
  939. /*++
  940. Routine Description:
  941. This function queries a specified line device to determine its telephony
  942. capabilities. The returned information is valid for all addresses on the
  943. line device.
  944. Line device ID numbering for a Service Provider is sequential from the
  945. value set by the function TSPI_lineSetDeviceIDBase.
  946. The dwExtVersion field of pLineDevCaps has already been filled in to
  947. indicate the version number of the Extension information requested. If
  948. it is zero, no Extension information is requested. If it is non-zero it
  949. holds a value that has already been negotiated for this device with the
  950. function TSPI_lineNegotiateExtVersion. The Service Provider should fill
  951. in Extension information according to the Extension version specified.
  952. One of the fields in the LINEDEVCAPS structure returned by this function
  953. contains the number of addresses assigned to the specified line device.
  954. The actual address IDs used to reference individual addresses vary from
  955. zero to one less than the returned number. The capabilities of each
  956. address may be different. Use TSPI_lineGetAddressCaps for each available
  957. <dwDeviceID, dwAddressID> combination to determine the exact capabilities
  958. of each address.
  959. Arguments:
  960. dwDeviceID - Specifies the line device to be queried.
  961. dwTSPIVersion - Specifies the negotiated TSPI version number. This value
  962. has already been negotiated for this device through the
  963. TSPI_lineNegotiateTSPIVersion function.
  964. pLineDevCaps - Specifies a far pointer to a variable sized structure of
  965. type LINEDEVCAPS. Upon successful completion of the request, this
  966. structure is filled with line device capabilities information.
  967. Return Values:
  968. Returns zero if the function is successful or a negative error
  969. number if an error has occurred. Possible error returns are:
  970. LINEERR_BADDEVICEID - The specified line device ID is out of range.
  971. LINEERR_INCOMPATIBLEAPIVERSION - The application requested an API
  972. version or version range that is either incompatible or cannot
  973. be supported by the Telephony API implementation and/or
  974. corresponding service provider.
  975. LINEERR_STRUCTURETOOSMALL - The dwTotalSize member of a structure
  976. does not specify enough memory to contain the fixed portion of
  977. the structure. The dwNeededSize field has been set to the amount
  978. required.
  979. --*/
  980. {
  981. DWORD dwLineNameSize;
  982. DWORD dwProviderInfoSize;
  983. PH323_LINE pLine = NULL;
  984. // make sure this is a version we support
  985. if (!H323ValidateTSPIVersion(dwTSPIVersion)) {
  986. // do not support tspi version
  987. return LINEERR_INCOMPATIBLEAPIVERSION;
  988. }
  989. // make sure this is a version we support
  990. if (!H323ValidateExtVersion(dwExtVersion)) {
  991. // do not support extensions
  992. return LINEERR_INVALEXTVERSION;
  993. }
  994. // retrieve line device pointer from device id
  995. if (!H323GetLineFromIDAndLock(&pLine, dwDeviceID)) {
  996. // invalid line device id
  997. return LINEERR_BADDEVICEID;
  998. }
  999. // determine string lengths
  1000. dwProviderInfoSize = H323SizeOfWSZ(g_pwszProviderInfo);
  1001. dwLineNameSize = H323SizeOfWSZ(g_pwszLineName);
  1002. // calculate number of bytes required
  1003. pLineDevCaps->dwNeededSize = sizeof(LINEDEVCAPS) +
  1004. dwProviderInfoSize +
  1005. dwLineNameSize
  1006. ;
  1007. // make sure buffer is large enough for variable length data
  1008. if (pLineDevCaps->dwTotalSize >= pLineDevCaps->dwNeededSize) {
  1009. // record amount of memory used
  1010. pLineDevCaps->dwUsedSize = pLineDevCaps->dwNeededSize;
  1011. // position provider info after fixed portion
  1012. pLineDevCaps->dwProviderInfoSize = dwProviderInfoSize;
  1013. pLineDevCaps->dwProviderInfoOffset = sizeof(LINEDEVCAPS);
  1014. // position line name after device class
  1015. pLineDevCaps->dwLineNameSize = dwLineNameSize;
  1016. pLineDevCaps->dwLineNameOffset =
  1017. pLineDevCaps->dwProviderInfoOffset +
  1018. pLineDevCaps->dwProviderInfoSize
  1019. ;
  1020. // copy provider info after fixed portion
  1021. memcpy((LPBYTE)pLineDevCaps + pLineDevCaps->dwProviderInfoOffset,
  1022. (LPBYTE)g_pwszProviderInfo,
  1023. pLineDevCaps->dwProviderInfoSize
  1024. );
  1025. // copy line name after device class
  1026. memcpy((LPBYTE)pLineDevCaps + pLineDevCaps->dwLineNameOffset,
  1027. (LPBYTE)g_pwszLineName,
  1028. pLineDevCaps->dwLineNameSize
  1029. );
  1030. } else if (pLineDevCaps->dwTotalSize >= sizeof(LINEDEVCAPS)) {
  1031. H323DBG((
  1032. DEBUG_LEVEL_WARNING,
  1033. "linedevcaps structure too small for strings.\n"
  1034. ));
  1035. // structure only contains fixed portion
  1036. pLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS);
  1037. } else {
  1038. H323DBG((
  1039. DEBUG_LEVEL_WARNING,
  1040. "linedevcaps structure too small.\n"
  1041. ));
  1042. // release line device
  1043. H323UnlockLine(pLine);
  1044. // structure is too small
  1045. return LINEERR_STRUCTURETOOSMALL;
  1046. }
  1047. H323DBG((
  1048. DEBUG_LEVEL_VERBOSE,
  1049. "line %d capabilities requested.\n",
  1050. pLine->dwDeviceID
  1051. ));
  1052. // construct permanent line identifier
  1053. pLineDevCaps->dwPermanentLineID = (DWORD)MAKELONG(
  1054. dwDeviceID - g_dwLineDeviceIDBase,
  1055. g_dwPermanentProviderID
  1056. );
  1057. // notify tapi that strings returned are in unicode
  1058. pLineDevCaps->dwStringFormat = STRINGFORMAT_UNICODE;
  1059. // initialize line device capabilities
  1060. pLineDevCaps->dwNumAddresses = H323_MAXADDRSPERLINE;
  1061. pLineDevCaps->dwMaxNumActiveCalls = H323_MAXCALLSPERLINE;
  1062. pLineDevCaps->dwAddressModes = H323_LINE_ADDRESSMODES;
  1063. pLineDevCaps->dwBearerModes = H323_LINE_BEARERMODES;
  1064. pLineDevCaps->dwDevCapFlags = H323_LINE_DEVCAPFLAGS;
  1065. pLineDevCaps->dwLineFeatures = H323_LINE_LINEFEATURES;
  1066. pLineDevCaps->dwMaxRate = H323_LINE_MAXRATE;
  1067. pLineDevCaps->dwMediaModes = H323_LINE_MEDIAMODES;
  1068. pLineDevCaps->dwRingModes = 0;
  1069. // initialize address types to include phone numbers
  1070. pLineDevCaps->dwAddressTypes = H323_LINE_ADDRESSTYPES;
  1071. // line guid
  1072. memcpy(
  1073. &pLineDevCaps->PermanentLineGuid,
  1074. &LINE_H323,
  1075. sizeof(GUID)
  1076. );
  1077. // modify GUID to be unique for each line
  1078. pLineDevCaps->PermanentLineGuid.Data1 +=
  1079. dwDeviceID - g_dwLineDeviceIDBase;
  1080. // protocol guid
  1081. memcpy(
  1082. &pLineDevCaps->ProtocolGuid,
  1083. &TAPIPROTOCOL_H323,
  1084. sizeof(GUID)
  1085. );
  1086. // add dtmf support via H.245 user input messages
  1087. pLineDevCaps->dwGenerateDigitModes = LINEDIGITMODE_DTMF;
  1088. pLineDevCaps->dwMonitorDigitModes = LINEDIGITMODE_DTMF;
  1089. // release line device
  1090. H323UnlockLine(pLine);
  1091. // success
  1092. return NOERROR;
  1093. }
  1094. LONG
  1095. TSPIAPI
  1096. TSPI_lineGetLineDevStatus(
  1097. HDRVLINE hdLine,
  1098. LPLINEDEVSTATUS pLineDevStatus
  1099. )
  1100. /*++
  1101. Routine Description:
  1102. This operation enables the TAPI DLL to query the specified open line
  1103. device for its current status.
  1104. The TAPI DLL uses TSPI_lineGetLineDevStatus to query the line device
  1105. for its current line status. This status information applies globally
  1106. to all addresses on the line device. Use TSPI_lineGetAddressStatus to
  1107. determine status information about a specific address on a line.
  1108. Arguments:
  1109. hdLine - Specifies the Service Provider's opaque handle to the line
  1110. to be queried.
  1111. pLineDevStatus - Specifies a far pointer to a variable sized data
  1112. structure of type LINEDEVSTATUS. Upon successful completion of
  1113. the request, this structure is filled with the line's device status.
  1114. Return Values:
  1115. Returns zero if the function is successful or a negative error
  1116. number if an error has occurred. Possible error returns are:
  1117. LINEERR_INVALLINEHANDLE - The specified line device handle is invalid.
  1118. LINEERR_STRUCTURETOOSMALL - The dwTotalSize member of a structure does
  1119. not specify enough memory to contain the fixed portion of the
  1120. structure. The dwNeededSize field has been set to the amount
  1121. required.
  1122. --*/
  1123. {
  1124. PH323_LINE pLine = NULL;
  1125. // retrieve line device pointer from handle
  1126. if (!H323GetLineAndLock(&pLine, hdLine)) {
  1127. // invalid line device handle
  1128. return LINEERR_INVALLINEHANDLE;
  1129. }
  1130. // determine number of bytes needed
  1131. pLineDevStatus->dwNeededSize = sizeof(LINEDEVSTATUS);
  1132. // see if allocated structure is large enough
  1133. if (pLineDevStatus->dwTotalSize < pLineDevStatus->dwNeededSize) {
  1134. H323DBG((
  1135. DEBUG_LEVEL_ERROR,
  1136. "linedevstatus structure too small.\n"
  1137. ));
  1138. // release line device
  1139. H323UnlockLine(pLine);
  1140. // structure too small
  1141. return LINEERR_STRUCTURETOOSMALL;
  1142. }
  1143. // record number of bytes used
  1144. pLineDevStatus->dwUsedSize = pLineDevStatus->dwNeededSize;
  1145. // initialize supported line device status fields
  1146. pLineDevStatus->dwLineFeatures = H323_LINE_LINEFEATURES;
  1147. pLineDevStatus->dwDevStatusFlags = H323_LINE_DEVSTATUSFLAGS;
  1148. // determine number of active calls on the line device
  1149. pLineDevStatus->dwNumActiveCalls = pLine->pCallTable->dwNumInUse;
  1150. // release line device
  1151. H323UnlockLine(pLine);
  1152. // success
  1153. return NOERROR;
  1154. }
  1155. LONG
  1156. TSPIAPI
  1157. TSPI_lineGetNumAddressIDs(
  1158. HDRVLINE hdLine,
  1159. LPDWORD pdwNumAddressIDs
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. Retrieves the number of address IDs supported on the indicated line.
  1164. This function is called by TAPI.DLL in response to an application calling
  1165. lineSetNumRings, lineGetNumRings, or lineGetNewCalls. TAPI.DLL uses the
  1166. retrieved value to determine if the specified address ID is within the
  1167. range supported by the service provider.
  1168. Arguments:
  1169. hdLine - Specifies the handle to the line for which the number of address
  1170. IDs is to be retrieved.
  1171. pdwNumAddressIDs - Specifies a far pointer to a DWORD. The location is
  1172. filled with the number of address IDs supported on the indicated line.
  1173. The value should be one or larger.
  1174. Return Values:
  1175. Returns zero if the function is successful, or a negative error number
  1176. if an error has occurred. Possible return values are as follows:
  1177. LINEERR_INVALLINEHANDLE - The specified line device handle is invalid.
  1178. --*/
  1179. {
  1180. PH323_LINE pLine = NULL;
  1181. // retrieve line device pointer from handle
  1182. if (!H323GetLineAndLock(&pLine, hdLine)) {
  1183. // invalid line device handle
  1184. return LINEERR_INVALLINEHANDLE;
  1185. }
  1186. // transfer number of addresses
  1187. *pdwNumAddressIDs = H323_MAXADDRSPERLINE;
  1188. // release line device
  1189. H323UnlockLine(pLine);
  1190. // success
  1191. return NOERROR;
  1192. }
  1193. LONG
  1194. TSPIAPI
  1195. TSPI_lineOpen(
  1196. DWORD dwDeviceID,
  1197. HTAPILINE htLine,
  1198. LPHDRVLINE phdLine,
  1199. DWORD dwTSPIVersion,
  1200. LINEEVENT pfnEventProc
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. This function opens the line device whose device ID is given, returning
  1205. the Service Provider's opaque handle for the device and retaining the TAPI
  1206. DLL's opaque handle for the device for use in subsequent calls to the
  1207. LINEEVENT procedure.
  1208. Opening a line entitles the TAPI DLL to make further requests on the line.
  1209. The line becomes "active" in the sense that the TAPI DLL can initiate
  1210. outbound calls and the Service Provider can report inbound calls. The
  1211. Service Provider reserves whatever non-sharable resources are required to
  1212. manage the line. For example, opening a line accessed through a comm port
  1213. and modem should result in opening the comm port, making it no longer
  1214. available for use by other applications.
  1215. If the function is successful, both the TAPI DLL and the Service Provider
  1216. become committed to operating under the specified interface version number
  1217. for this open device. Subsquent operations and events identified using
  1218. the exchanged opaque line handles conform to that interface version. This
  1219. commitment and the validity of the handles remain in effect until the TAPI
  1220. DLL closes the line using the TSPI_lineClose operation or the Service
  1221. Provider reports the LINE_CLOSE event. If the function is not successful,
  1222. no such commitment is made and the handles are not valid.
  1223. Arguments:
  1224. dwDeviceID - Identifies the line device to be opened. The value
  1225. LINE_MAPPER for a device ID is not permitted.
  1226. htLine - Specifies the TAPI DLL's opaque handle for the line device to be
  1227. used in subsequent calls to the LINEEVENT callback procedure to
  1228. identify the device.
  1229. phdLine - A far pointer to a HDRVLINE where the Service Provider fills in
  1230. its opaque handle for the line device to be used by the TAPI DLL in
  1231. subsequent calls to identify the device.
  1232. dwTSPIVersion - The TSPI version negotiated through
  1233. TSPI_lineNegotiateTSPIVersion under which the Service Provider is
  1234. willing to operate.
  1235. pfnEventProc - A far pointer to the LINEEVENT callback procedure supplied
  1236. by the TAPI DLL that the Service Provider will call to report
  1237. subsequent events on the line.
  1238. Return Values:
  1239. Returns zero if the function is successful, or a negative error number
  1240. if an error has occurred. Possible return values are as follows:
  1241. LINEERR_BADDEVICEID - The specified line device ID is out of range.
  1242. LINEERR_INCOMPATIBLEAPIVERSION - The passed TSPI version or version
  1243. range did not match an interface version definition supported by
  1244. the service provider.
  1245. LINEERR_INUSE - The line device is in use and cannot currently be
  1246. configured, allow a party to be added, allow a call to be
  1247. answered, or allow a call to be placed.
  1248. LINEERR_OPERATIONFAILED - The operation failed for an unspecified or
  1249. unknown reason.
  1250. --*/
  1251. {
  1252. PH323_LINE pLine = NULL;
  1253. // make sure this is a version we support
  1254. if (!H323ValidateTSPIVersion(dwTSPIVersion)) {
  1255. // failure
  1256. return LINEERR_INCOMPATIBLEAPIVERSION;
  1257. }
  1258. // retrieve pointer to line device from device id
  1259. if (!H323GetLineFromIDAndLock(&pLine, dwDeviceID)) {
  1260. // do not recognize device
  1261. return LINEERR_BADDEVICEID;
  1262. }
  1263. // see if line device is closed
  1264. if (!H323IsLineClosed(pLine) &&
  1265. !pLine->fIsMarkedForDeletion) {
  1266. // see if line device is open
  1267. if (H323IsLineOpen(pLine)) {
  1268. H323DBG((
  1269. DEBUG_LEVEL_ERROR,
  1270. "line %d already opened.\n",
  1271. pLine->dwDeviceID
  1272. ));
  1273. // release line device
  1274. H323UnlockLine(pLine);
  1275. // line already in use
  1276. return LINEERR_INUSE;
  1277. }
  1278. // release line device
  1279. H323UnlockLine(pLine);
  1280. // line not intialized
  1281. return LINEERR_INVALLINESTATE;
  1282. }
  1283. // attempt to open line device
  1284. if (!H323OpenLine(pLine, htLine, dwTSPIVersion)) {
  1285. // release line device
  1286. H323UnlockLine(pLine);
  1287. // could not open line device
  1288. return LINEERR_OPERATIONFAILED;
  1289. }
  1290. // retrurn line handle
  1291. *phdLine = pLine->hdLine;
  1292. // release line device
  1293. H323UnlockLine(pLine);
  1294. // success
  1295. return NOERROR;
  1296. }
  1297. LONG
  1298. TSPIAPI
  1299. TSPI_lineCreateMSPInstance(
  1300. HDRVLINE hdLine,
  1301. DWORD dwAddressID,
  1302. HTAPIMSPLINE htMSPLine,
  1303. LPHDRVMSPLINE phdMSPLine
  1304. )
  1305. {
  1306. PH323_LINE pLine = NULL;
  1307. // retrieve line pointer from handle
  1308. if (!H323GetLineAndLock(&pLine, hdLine)) {
  1309. // invalid line handle
  1310. return LINEERR_INVALLINEHANDLE;
  1311. }
  1312. // We are not keeping the msp handles. Just fake a handle here.
  1313. *phdMSPLine = (HDRVMSPLINE)pLine->dwNextMSPHandle++;
  1314. // release line device
  1315. H323UnlockLine(pLine);
  1316. // success
  1317. return NOERROR;
  1318. }
  1319. LONG
  1320. TSPIAPI
  1321. TSPI_lineCloseMSPInstance(
  1322. HDRVMSPLINE hdMSPLine
  1323. )
  1324. {
  1325. // success
  1326. return NOERROR;
  1327. }