Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1110 lines
25 KiB

  1. #include "std.h"
  2. // This is the communications mask used by our serial port. More may be
  3. // necessary, but for right now, this seems to work.
  4. #define EV_SERIAL EV_RXCHAR | EV_ERR | EV_BREAK
  5. #define SERIALPORT_NAME L"Serial Port"
  6. // This GUID is used to identify objects opened by this library. It is
  7. // placed in the m_Secret member of the SERIALPORT structure. Any external
  8. // interface accepting a SERIALPORT object as a parameter should check this
  9. // out before using the structure.
  10. static const GUID uuidSerialPortObjectGuid =
  11. { 0x86ae9c9b, 0x9444, 0x4d00, { 0x84, 0xbb, 0xc1, 0xd9, 0xc2, 0xd9, 0xfb, 0xf3 } };
  12. // Structure defining an open serial port object. All external users of this
  13. // library will only have a void pointer to one of these, and the structure is
  14. // not published anywhere. This abstration makes it more difficult for the
  15. // user to mess things up.
  16. typedef struct __SERIALPORT
  17. {
  18. GUID m_Secret; // Identifies this as a serial port
  19. HANDLE m_hPort; // Handle to the opened serial port
  20. HANDLE m_hAbort; // Event signalled when port is closing
  21. HANDLE m_hReadMutex; // Only one thread allowed to read a port
  22. HANDLE m_hWriteMutex; // Only one thread allowed to read a port
  23. HANDLE m_hCloseMutex; // Only one thread allowed to close a port
  24. HANDLE m_hReadComplete; // Event to signal read completion
  25. HANDLE m_hWriteComplete; // Event to signal write completion
  26. } SERIALPORT, *PSERIALPORT;
  27. extern PVOID APIENTRY lhcOpen(
  28. PCWSTR pcszPortSpec);
  29. extern BOOL APIENTRY lhcRead(
  30. PVOID pObject,
  31. PVOID pBuffer,
  32. DWORD dwSize,
  33. PDWORD pdwBytesRead);
  34. extern BOOL APIENTRY lhcWrite(
  35. PVOID pObject,
  36. PVOID pBuffer,
  37. DWORD dwSize);
  38. extern BOOL APIENTRY lhcClose(
  39. PVOID pObject);
  40. extern DWORD APIENTRY lhcGetLibraryName(
  41. PWSTR pszBuffer,
  42. DWORD dwSize);
  43. BOOL lhcpAcquireWithAbort(
  44. HANDLE hMutex,
  45. HANDLE hAbort);
  46. BOOL lhcpAcquireReadWithAbort(
  47. PSERIALPORT pObject);
  48. BOOL lhcpAcquireWriteWithAbort(
  49. PSERIALPORT pObject);
  50. BOOL lhcpAcquireCloseWithAbort(
  51. PSERIALPORT pObject);
  52. BOOL lhcpAcquireReadAndWrite(
  53. PSERIALPORT pObject);
  54. BOOL lhcpReleaseRead(
  55. PSERIALPORT pObject);
  56. BOOL lhcpReleaseWrite(
  57. PSERIALPORT pObject);
  58. BOOL lhcpReleaseClose(
  59. PSERIALPORT pObject);
  60. BOOL lhcpIsValidObject(
  61. PSERIALPORT pObject);
  62. PSERIALPORT lhcpCreateNewObject();
  63. void lhcpDeleteObject(
  64. PSERIALPORT pObject);
  65. BOOL lhcpParseParameters(
  66. PCWSTR pcszPortSpec,
  67. PWSTR* pszPort,
  68. PDWORD pdwBaudRate);
  69. void lhcpParseParametersFree(
  70. PWSTR* pszPort,
  71. PDWORD pdwBaudRate);
  72. BOOL lhcpSetCommState(
  73. HANDLE hPort,
  74. DWORD dwBaudRate);
  75. BOOL lhcpWaitForCommEvent(
  76. PSERIALPORT pObject,
  77. PDWORD pdwEventMask);
  78. BOOL lhcpReadCommPort(
  79. PSERIALPORT pObject,
  80. PVOID pBuffer,
  81. DWORD dwSize,
  82. PDWORD pdwBytesRead);
  83. BOOL lhcpWriteCommPort(
  84. PSERIALPORT pObject,
  85. PVOID pBuffer,
  86. DWORD dwSize);
  87. BOOL lhcpAcquireWithAbort(HANDLE hMutex, HANDLE hAbort)
  88. {
  89. HANDLE hWaiters[2];
  90. DWORD dwWaitResult;
  91. hWaiters[0] = hAbort;
  92. hWaiters[1] = hMutex;
  93. // We should honour the m_hAbort event, since this is signalled when the
  94. // port is closed by another thread
  95. dwWaitResult = WaitForMultipleObjects(
  96. 2,
  97. hWaiters,
  98. FALSE,
  99. INFINITE);
  100. if (WAIT_OBJECT_0==dwWaitResult)
  101. {
  102. goto Error;
  103. }
  104. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  105. {
  106. // This should never, ever happen - so I will put a debug breapoint
  107. // in here (checked only).
  108. #ifdef DBG
  109. DebugBreak();
  110. #endif
  111. goto Error;
  112. }
  113. return TRUE; // We have acquired the write mutex
  114. Error:
  115. return FALSE; // We have aborted
  116. }
  117. BOOL lhcpAcquireReadWithAbort(PSERIALPORT pObject)
  118. {
  119. return lhcpAcquireWithAbort(
  120. pObject->m_hReadMutex,
  121. pObject->m_hAbort);
  122. }
  123. BOOL lhcpAcquireWriteWithAbort(PSERIALPORT pObject)
  124. {
  125. return lhcpAcquireWithAbort(
  126. pObject->m_hWriteMutex,
  127. pObject->m_hAbort);
  128. }
  129. BOOL lhcpAcquireCloseWithAbort(PSERIALPORT pObject)
  130. {
  131. return lhcpAcquireWithAbort(
  132. pObject->m_hCloseMutex,
  133. pObject->m_hAbort);
  134. }
  135. BOOL lhcpAcquireReadAndWrite(PSERIALPORT pObject)
  136. {
  137. HANDLE hWaiters[2];
  138. DWORD dwWaitResult;
  139. hWaiters[0] = pObject->m_hReadMutex;
  140. hWaiters[1] = pObject->m_hWriteMutex;
  141. dwWaitResult = WaitForMultipleObjects(
  142. 2,
  143. hWaiters,
  144. TRUE,
  145. 1000); // Timeout after 1 second
  146. if (WAIT_OBJECT_0!=dwWaitResult)
  147. {
  148. goto Error;
  149. }
  150. return TRUE; // We have acquired the write mutex
  151. Error:
  152. return FALSE; // We have aborted
  153. }
  154. BOOL lhcpReleaseRead(PSERIALPORT pObject)
  155. {
  156. return ReleaseMutex(
  157. pObject->m_hReadMutex);
  158. }
  159. BOOL lhcpReleaseWrite(PSERIALPORT pObject)
  160. {
  161. return ReleaseMutex(
  162. pObject->m_hWriteMutex);
  163. }
  164. BOOL lhcpReleaseClose(PSERIALPORT pObject)
  165. {
  166. return ReleaseMutex(
  167. pObject->m_hCloseMutex);
  168. }
  169. BOOL lhcpIsValidObject(PSERIALPORT pObject)
  170. {
  171. BOOL bResult;
  172. __try
  173. {
  174. bResult = IsEqualGUID(
  175. &uuidSerialPortObjectGuid,
  176. &pObject->m_Secret);
  177. }
  178. __except(EXCEPTION_EXECUTE_HANDLER)
  179. {
  180. SetLastError(
  181. ERROR_INVALID_HANDLE);
  182. bResult = FALSE;
  183. goto Done;
  184. }
  185. Done:
  186. return bResult;
  187. }
  188. PSERIALPORT lhcpCreateNewObject()
  189. {
  190. PSERIALPORT pObject = (PSERIALPORT)malloc(
  191. sizeof(SERIALPORT));
  192. if (pObject!=NULL)
  193. {
  194. pObject->m_Secret = uuidSerialPortObjectGuid;
  195. pObject->m_hPort = INVALID_HANDLE_VALUE;
  196. pObject->m_hAbort = NULL;
  197. pObject->m_hReadMutex = NULL; // Only one thread allowed to read a port
  198. pObject->m_hWriteMutex = NULL; // Only one thread allowed to read a port
  199. pObject->m_hCloseMutex = NULL; // Only one thread allowed to read a port
  200. pObject->m_hReadComplete = NULL; // Event to signal read completion
  201. pObject->m_hWriteComplete = NULL; // Event to signal write completion
  202. }
  203. else
  204. {
  205. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  206. }
  207. return pObject;
  208. }
  209. void lhcpDeleteObject(PSERIALPORT pObject)
  210. {
  211. if (pObject==NULL)
  212. {
  213. return;
  214. }
  215. ZeroMemory(
  216. &(pObject->m_Secret),
  217. sizeof(pObject->m_Secret));
  218. if (pObject->m_hPort!=INVALID_HANDLE_VALUE)
  219. {
  220. CloseHandle(
  221. pObject->m_hPort);
  222. }
  223. if (pObject->m_hAbort!=NULL)
  224. {
  225. CloseHandle(
  226. pObject->m_hAbort);
  227. }
  228. if (pObject->m_hReadMutex!=NULL)
  229. {
  230. CloseHandle(
  231. pObject->m_hReadMutex);
  232. }
  233. if (pObject->m_hWriteMutex!=NULL)
  234. {
  235. CloseHandle(
  236. pObject->m_hWriteMutex);
  237. }
  238. if (pObject->m_hCloseMutex!=NULL)
  239. {
  240. CloseHandle(
  241. pObject->m_hCloseMutex);
  242. }
  243. if (pObject->m_hReadComplete!=NULL)
  244. {
  245. CloseHandle(
  246. pObject->m_hReadComplete);
  247. }
  248. if (pObject->m_hWriteComplete!=NULL)
  249. {
  250. CloseHandle(
  251. pObject->m_hWriteComplete);
  252. }
  253. FillMemory(
  254. pObject,
  255. sizeof(SERIALPORT),
  256. 0x00);
  257. free(
  258. pObject);
  259. }
  260. BOOL lhcpParseParameters(PCWSTR pcszPortSpec, PWSTR* pszPort, PDWORD pdwBaudRate)
  261. {
  262. PWSTR pszSettings;
  263. *pszPort = malloc(
  264. (wcslen(pcszPortSpec) + 5) * sizeof(WCHAR));
  265. if (NULL==*pszPort)
  266. {
  267. SetLastError(
  268. ERROR_NOT_ENOUGH_MEMORY);
  269. goto Error;
  270. }
  271. wcscpy(
  272. *pszPort,
  273. L"\\\\.\\"); // Append the device prefix to the port name
  274. wcscat(
  275. *pszPort,
  276. pcszPortSpec);
  277. pszSettings = wcschr( // Find where the settings start
  278. *pszPort,
  279. L'@');
  280. if (NULL==pszSettings)
  281. {
  282. SetLastError(
  283. ERROR_INVALID_PARAMETER);
  284. goto Error;
  285. }
  286. *pszSettings++ = L'\0'; // Separate the strings
  287. *pdwBaudRate = 0;
  288. while (*pszSettings!=L'\0' && *pdwBaudRate<115200)
  289. {
  290. if (L'0'<=*pszSettings && *pszSettings<=L'9')
  291. {
  292. *pdwBaudRate *= 10;
  293. *pdwBaudRate += *pszSettings - L'0';
  294. pszSettings++;
  295. }
  296. else
  297. {
  298. break;
  299. }
  300. }
  301. if (*pszSettings!=L'0' && *pdwBaudRate!=9600 && *pdwBaudRate!=19200 &&
  302. *pdwBaudRate!=38400 && *pdwBaudRate!=57600 && *pdwBaudRate!=115200)
  303. {
  304. SetLastError(
  305. ERROR_INVALID_PARAMETER);
  306. goto Error;
  307. }
  308. return TRUE;
  309. Error:
  310. lhcpParseParametersFree(
  311. pszPort, pdwBaudRate);
  312. return FALSE;
  313. }
  314. void lhcpParseParametersFree(PWSTR* pszPort, PDWORD pdwBaudRate)
  315. {
  316. if (*pszPort != NULL)
  317. {
  318. free(*pszPort);
  319. *pszPort = NULL;
  320. }
  321. *pdwBaudRate = 0;
  322. }
  323. BOOL lhcpSetCommState(HANDLE hPort, DWORD dwBaudRate)
  324. {
  325. DCB MyDCB;
  326. COMMTIMEOUTS CommTimeouts;
  327. BOOL bResult;
  328. ZeroMemory(
  329. &MyDCB,
  330. sizeof(DCB));
  331. MyDCB.DCBlength = sizeof(DCB);
  332. MyDCB.BaudRate = dwBaudRate;
  333. MyDCB.fBinary = 1;
  334. MyDCB.fParity = 1;
  335. MyDCB.fOutxCtsFlow = 0;
  336. MyDCB.fOutxDsrFlow = 0;
  337. MyDCB.fDtrControl = 1;
  338. MyDCB.fDsrSensitivity = 0;
  339. MyDCB.fTXContinueOnXoff = 1;
  340. MyDCB.fOutX = 1;
  341. MyDCB.fInX = 1;
  342. MyDCB.fErrorChar = 0;
  343. MyDCB.fNull = 0;
  344. MyDCB.fRtsControl = 1;
  345. MyDCB.fAbortOnError = 0;
  346. MyDCB.XonLim = 0x50;
  347. MyDCB.XoffLim = 0xc8;
  348. MyDCB.ByteSize = 0x8;
  349. MyDCB.Parity = 0;
  350. MyDCB.StopBits = 0;
  351. MyDCB.XonChar = 17;
  352. MyDCB.XoffChar = 19;
  353. MyDCB.ErrorChar = 0;
  354. MyDCB.EofChar = 0;
  355. MyDCB.EvtChar = 0;
  356. bResult = SetCommState(
  357. hPort,
  358. &MyDCB);
  359. if (!bResult)
  360. {
  361. goto Error;
  362. }
  363. CommTimeouts.ReadIntervalTimeout = 0xffffffff; //MAXDWORD
  364. CommTimeouts.ReadTotalTimeoutMultiplier = 0x0; //MAXDWORD
  365. CommTimeouts.ReadTotalTimeoutConstant = 0x0;
  366. CommTimeouts.WriteTotalTimeoutMultiplier = 0;
  367. CommTimeouts.WriteTotalTimeoutConstant = 0;
  368. bResult = SetCommTimeouts(
  369. hPort,
  370. &CommTimeouts);
  371. if (!bResult)
  372. {
  373. goto Error;
  374. }
  375. bResult = SetCommMask(
  376. hPort,
  377. EV_SERIAL);
  378. if (!bResult)
  379. {
  380. goto Error;
  381. }
  382. return TRUE;
  383. Error:
  384. return FALSE;
  385. }
  386. BOOL lhcpWaitForCommEvent(PSERIALPORT pObject, PDWORD pdwEventMask)
  387. {
  388. OVERLAPPED Overlapped;
  389. BOOL bResult;
  390. HANDLE hWaiters[2];
  391. DWORD dwWaitResult;
  392. DWORD dwBytesTransferred;
  393. // I have no idea whether this is necessary, so I will do it just to be
  394. // on the safe side.
  395. ZeroMemory(
  396. &Overlapped,
  397. sizeof(OVERLAPPED));
  398. Overlapped.hEvent = pObject->m_hReadComplete;
  399. // Start waiting for a comm event
  400. bResult = WaitCommEvent(
  401. pObject->m_hPort,
  402. pdwEventMask,
  403. &Overlapped);
  404. if (!bResult && GetLastError()!=ERROR_IO_PENDING)
  405. {
  406. goto Error;
  407. }
  408. hWaiters[0] = pObject->m_hAbort;
  409. hWaiters[1] = pObject->m_hReadComplete;
  410. // Let's wait for the operation to complete. This will quit waiting if
  411. // the m_hAbort event is signalled.
  412. dwWaitResult = WaitForMultipleObjects(
  413. 2,
  414. hWaiters,
  415. FALSE,
  416. INFINITE);
  417. if (WAIT_OBJECT_0==dwWaitResult)
  418. {
  419. // The m_hAbort event was signalled. This means that Close was called
  420. // on this serial port object. So let's cancel the pending IO.
  421. CancelIo(
  422. pObject->m_hPort);
  423. // The serial port object is being closed, so let's call it invalid.
  424. SetLastError(
  425. ERROR_INVALID_HANDLE);
  426. goto Error;
  427. }
  428. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  429. {
  430. // This should never, ever happen - so I will put a debug breapoint
  431. // in here (checked only).
  432. #ifdef DBG
  433. DebugBreak();
  434. #endif
  435. goto Error;
  436. }
  437. // Check the success or failure of the operation
  438. bResult = GetOverlappedResult(
  439. pObject->m_hPort,
  440. &Overlapped,
  441. &dwBytesTransferred,
  442. TRUE);
  443. if (!bResult)
  444. {
  445. goto Error;
  446. }
  447. return TRUE;
  448. Error:
  449. return FALSE;
  450. }
  451. BOOL lhcpReadCommPort(
  452. PSERIALPORT pObject,
  453. PVOID pBuffer,
  454. DWORD dwSize,
  455. PDWORD pdwBytesRead)
  456. {
  457. OVERLAPPED Overlapped;
  458. BOOL bResult;
  459. DWORD dwWaitResult;
  460. HANDLE hWaiters[2];
  461. // I have no idea whether this is necessary, so I will do it just to be
  462. // on the safe side.
  463. ZeroMemory(
  464. &Overlapped,
  465. sizeof(OVERLAPPED));
  466. Overlapped.hEvent = pObject->m_hReadComplete;
  467. // We can now read the comm port
  468. bResult = ReadFile(
  469. pObject->m_hPort,
  470. pBuffer,
  471. dwSize,
  472. pdwBytesRead,
  473. &Overlapped);
  474. if (!bResult && GetLastError()!=ERROR_IO_PENDING)
  475. {
  476. goto Error;
  477. }
  478. hWaiters[0] = pObject->m_hAbort;
  479. hWaiters[1] = pObject->m_hReadComplete;
  480. // Let's wait for the operation to complete. This will quit waiting if
  481. // the m_hAbort event is signalled.
  482. dwWaitResult = WaitForMultipleObjects(
  483. 2,
  484. hWaiters,
  485. FALSE,
  486. INFINITE);
  487. if (WAIT_OBJECT_0==dwWaitResult)
  488. {
  489. // The m_hAbort event was signalled. This means that Close was called
  490. // on this serial port object. So let's cancel the pending IO.
  491. CancelIo(
  492. pObject->m_hPort);
  493. // The serial port object is being closed, so let's call it invalid.
  494. SetLastError(
  495. ERROR_INVALID_HANDLE);
  496. goto Error;
  497. }
  498. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  499. {
  500. // This should never, ever happen - so I will put a debug breapoint
  501. // in here (checked only).
  502. #ifdef DBG
  503. DebugBreak();
  504. #endif
  505. goto Error;
  506. }
  507. // Check the success or failure of the read operation
  508. bResult = GetOverlappedResult(
  509. pObject->m_hPort,
  510. &Overlapped,
  511. pdwBytesRead,
  512. TRUE);
  513. if (!bResult)
  514. {
  515. goto Error;
  516. }
  517. return TRUE;
  518. Error:
  519. return FALSE;
  520. }
  521. BOOL lhcpWriteCommPort(
  522. PSERIALPORT pObject,
  523. PVOID pBuffer,
  524. DWORD dwSize)
  525. {
  526. OVERLAPPED Overlapped;
  527. BOOL bResult;
  528. DWORD dwBytesWritten;
  529. DWORD dwWaitResult;
  530. HANDLE hWaiters[2];
  531. // I have no idea whether this is necessary, so I will do it just to be
  532. // on the safe side.
  533. ZeroMemory(
  534. &Overlapped,
  535. sizeof(OVERLAPPED));
  536. Overlapped.hEvent = pObject->m_hWriteComplete;
  537. // We can now read the comm port
  538. bResult = WriteFile(
  539. pObject->m_hPort,
  540. pBuffer,
  541. dwSize,
  542. &dwBytesWritten,
  543. &Overlapped);
  544. if (!bResult && GetLastError()!=ERROR_IO_PENDING)
  545. {
  546. goto Error;
  547. }
  548. hWaiters[0] = pObject->m_hAbort;
  549. hWaiters[1] = pObject->m_hWriteComplete;
  550. // Let's wait for the operation to complete. This will quit waiting if
  551. // the m_hAbort event is signalled. If the read operation completed
  552. // immediately, then this wait will succeed immediately.
  553. dwWaitResult = WaitForMultipleObjects(
  554. 2,
  555. hWaiters,
  556. FALSE,
  557. INFINITE);
  558. if (WAIT_OBJECT_0==dwWaitResult)
  559. {
  560. // The m_hAbort event was signalled. This means that Close was called
  561. // on this serial port object. So let's cancel the pending IO.
  562. CancelIo(
  563. pObject->m_hPort);
  564. // The serial port object is being closed, so let's call it invalid.
  565. SetLastError(
  566. ERROR_INVALID_HANDLE);
  567. goto Error;
  568. }
  569. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  570. {
  571. // This should never, ever happen - so I will put a debug breapoint
  572. // in here (checked only).
  573. #ifdef DBG
  574. DebugBreak();
  575. #endif
  576. goto Error;
  577. }
  578. // Check the success or failure of the write operation
  579. bResult = GetOverlappedResult(
  580. pObject->m_hPort,
  581. &Overlapped,
  582. &dwBytesWritten,
  583. TRUE);
  584. if (!bResult)
  585. {
  586. goto Error;
  587. }
  588. return TRUE;
  589. Error:
  590. return FALSE;
  591. }
  592. extern PVOID APIENTRY lhcOpen(PCWSTR pcszPortSpec)
  593. {
  594. BOOL bResult;
  595. PWSTR pszPort;
  596. DWORD dwBaudRate;
  597. PSERIALPORT pObject = NULL;
  598. DCB MyDCB;
  599. bResult = lhcpParseParameters(
  600. pcszPortSpec,
  601. &pszPort,
  602. &dwBaudRate);
  603. if (!bResult)
  604. {
  605. goto Error;
  606. }
  607. // Allocate space and initialize the serial port object
  608. pObject = lhcpCreateNewObject();
  609. if (NULL==pObject)
  610. {
  611. goto Error;
  612. }
  613. // Open the serial port
  614. pObject->m_hPort = CreateFileW(
  615. pszPort,
  616. GENERIC_ALL,
  617. 0,
  618. NULL,
  619. OPEN_EXISTING,
  620. FILE_FLAG_OVERLAPPED,
  621. NULL);
  622. if (INVALID_HANDLE_VALUE==pObject->m_hPort)
  623. {
  624. goto Error;
  625. }
  626. // Set the properties of the serial port
  627. bResult = lhcpSetCommState(
  628. pObject->m_hPort,
  629. dwBaudRate);
  630. if (!bResult)
  631. {
  632. goto Error;
  633. }
  634. // This event will be set when we want to close the port
  635. pObject->m_hAbort = CreateEvent(
  636. NULL,
  637. TRUE,
  638. FALSE,
  639. NULL);
  640. if (NULL==pObject->m_hAbort)
  641. {
  642. goto Error;
  643. }
  644. // This event will be used for overlapped reading from the port
  645. pObject->m_hReadComplete = CreateEvent(
  646. NULL,
  647. TRUE,
  648. FALSE,
  649. NULL);
  650. if (NULL==pObject->m_hReadComplete)
  651. {
  652. goto Error;
  653. }
  654. // This event will be used for overlapped writing to the port
  655. pObject->m_hWriteComplete = CreateEvent(
  656. NULL,
  657. TRUE,
  658. FALSE,
  659. NULL);
  660. if (NULL==pObject->m_hWriteComplete)
  661. {
  662. goto Error;
  663. }
  664. // This mutex will ensure that only one thread can read at a time
  665. pObject->m_hReadMutex = CreateMutex(
  666. NULL,
  667. FALSE,
  668. NULL);
  669. if (NULL==pObject->m_hReadMutex)
  670. {
  671. goto Error;
  672. }
  673. // This mutex will ensure that only one thread can write at a time
  674. pObject->m_hWriteMutex = CreateMutex(
  675. NULL,
  676. FALSE,
  677. NULL);
  678. if (NULL==pObject->m_hWriteMutex)
  679. {
  680. goto Error;
  681. }
  682. // This mutex will ensure that only one thread can close the port
  683. pObject->m_hCloseMutex = CreateMutex(
  684. NULL,
  685. FALSE,
  686. NULL);
  687. if (NULL==pObject->m_hCloseMutex)
  688. {
  689. goto Error;
  690. }
  691. // Free up the temporary memory used to parse the parameters
  692. lhcpParseParametersFree(
  693. &pszPort, &dwBaudRate);
  694. // Return a pointer to the new object
  695. return pObject;
  696. Error:
  697. lhcpParseParametersFree(
  698. &pszPort, &dwBaudRate);
  699. lhcpDeleteObject(
  700. pObject);
  701. return NULL;
  702. }
  703. extern BOOL APIENTRY lhcRead(
  704. PVOID pObject,
  705. PVOID pBuffer,
  706. DWORD dwSize,
  707. PDWORD pdwBytesRead)
  708. {
  709. OVERLAPPED Overlapped;
  710. DWORD dwEventMask;
  711. BOOL bResult;
  712. // Firstly, we need to check whether the pointer that got passed in
  713. // points to a valid SERIALPORT object
  714. if (!lhcpIsValidObject(pObject))
  715. {
  716. goto NoMutex;
  717. }
  718. bResult = lhcpAcquireReadWithAbort(
  719. (PSERIALPORT)pObject);
  720. if (!bResult)
  721. {
  722. SetLastError(
  723. ERROR_INVALID_HANDLE);
  724. goto NoMutex;
  725. }
  726. // We need to check whether there are already some characters waiting.
  727. // WaitCommEvent will never complete if there are characters waiting
  728. // and no new characters arrive at the serial port. It's not cool, but
  729. // that's the way that it is.
  730. bResult = lhcpReadCommPort(
  731. (PSERIALPORT)pObject,
  732. pBuffer,
  733. dwSize,
  734. pdwBytesRead);
  735. if (*pdwBytesRead==0)
  736. {
  737. // Wait for something to happen to the serial port
  738. bResult = lhcpWaitForCommEvent(
  739. (PSERIALPORT)pObject, &dwEventMask);
  740. if (!bResult)
  741. {
  742. goto Error;
  743. }
  744. // We should now have a valid serial port event, so let's read the port.
  745. bResult = lhcpReadCommPort(
  746. (PSERIALPORT)pObject,
  747. pBuffer,
  748. dwSize,
  749. pdwBytesRead);
  750. if (!bResult)
  751. {
  752. goto Error;
  753. }
  754. }
  755. lhcpReleaseRead(
  756. (PSERIALPORT)pObject);
  757. return TRUE;
  758. Error:
  759. lhcpReleaseRead(
  760. (PSERIALPORT)pObject);
  761. NoMutex:
  762. return FALSE;
  763. }
  764. extern BOOL APIENTRY lhcWrite(
  765. PVOID pObject,
  766. PVOID pBuffer,
  767. DWORD dwSize)
  768. {
  769. OVERLAPPED Overlapped;
  770. BOOL bResult;
  771. // Firstly, we need to check whether the pointer that got passed in
  772. // points to a valid SERIALPORT object
  773. if (!lhcpIsValidObject(pObject))
  774. {
  775. goto NoMutex;
  776. }
  777. // Block until it is your turn
  778. bResult = lhcpAcquireWriteWithAbort(
  779. pObject);
  780. if (!bResult)
  781. {
  782. SetLastError(
  783. ERROR_INVALID_HANDLE);
  784. goto NoMutex;
  785. }
  786. // Wait for something to happen to the serial port
  787. bResult = lhcpWriteCommPort(
  788. (PSERIALPORT)pObject,
  789. pBuffer,
  790. dwSize);
  791. if (!bResult)
  792. {
  793. goto Error;
  794. }
  795. lhcpReleaseWrite(
  796. (PSERIALPORT)pObject);
  797. return TRUE;
  798. Error:
  799. lhcpReleaseWrite(
  800. (PSERIALPORT)pObject);
  801. NoMutex:
  802. return FALSE;
  803. }
  804. extern BOOL APIENTRY lhcClose(PVOID pObject)
  805. {
  806. BOOL bResult;
  807. // Firstly, we need to check whether the pointer that got passed in
  808. // points to a valid SERIALPORT object
  809. if (!lhcpIsValidObject(pObject))
  810. {
  811. goto NoMutex;
  812. }
  813. // We need to ensure that we are the only thread closing this object
  814. bResult = lhcpAcquireCloseWithAbort(
  815. pObject);
  816. if (!bResult)
  817. {
  818. SetLastError(
  819. ERROR_INVALID_HANDLE);
  820. goto NoMutex;
  821. }
  822. // Signal everyone to quit doing what they're doing. Any new threads
  823. // calling lhcRead and lhcWrite will be immediately sent packing, since
  824. // the m_hAbort event is waited on along with the relevant mutex.
  825. bResult = SetEvent(
  826. ((PSERIALPORT)pObject)->m_hAbort);
  827. if (!bResult)
  828. {
  829. goto Error;
  830. }
  831. // Now acquire the read and write mutexes so that no-one else will try to
  832. // access this object to read or write. Abort does not apply, since we
  833. // have already signalled it. We know that we are closing, and we need
  834. // the read and write mutexes.
  835. bResult = lhcpAcquireReadAndWrite(
  836. (PSERIALPORT)pObject);
  837. if (!bResult)
  838. {
  839. SetLastError(
  840. ERROR_INVALID_HANDLE);
  841. goto Error;
  842. }
  843. // Closes all of the open handles, erases the secret and frees up the
  844. // memory associated with the object. We can close the mutex objects,
  845. // even though we are the owners, since we can guarantee that no-one
  846. // else is waiting on them. The m_hAbort event being signalled will
  847. // ensure this.
  848. lhcpDeleteObject(
  849. (PSERIALPORT)pObject);
  850. return TRUE;
  851. Error:
  852. lhcpReleaseClose(
  853. (PSERIALPORT)pObject);
  854. lhcpDeleteObject(
  855. (PSERIALPORT)pObject);
  856. NoMutex:
  857. return FALSE;
  858. }
  859. extern DWORD APIENTRY lhcGetLibraryName(
  860. PWSTR pszBuffer,
  861. DWORD dwSize)
  862. {
  863. DWORD dwNameSize = wcslen(SERIALPORT_NAME)+1;
  864. // If zero is passed in as the buffer length, we will return the
  865. // required buffer size in characters, as calulated above. If the
  866. // incoming buffer size is not zero, and smaller than the required
  867. // buffer size, we return 0 (failure) with a valid error code. Notice
  868. // that in the case where the incoming size is zero, we don't touch
  869. // the buffer pointer at all.
  870. if (dwSize!=0 && dwSize < dwNameSize)
  871. {
  872. SetLastError(
  873. ERROR_INSUFFICIENT_BUFFER);
  874. dwNameSize = 0;
  875. }
  876. else
  877. {
  878. wcscpy(
  879. pszBuffer,
  880. SERIALPORT_NAME);
  881. }
  882. return dwNameSize;
  883. }
  884. extern void APIENTRY lhcUsage()
  885. {
  886. wprintf(
  887. L"Serial Port connection string:\n\n"
  888. L" <port>@<speed>\n\n"
  889. L"where <port> is the serial port to use and <speed> is the serial line\n"
  890. L"speed to use for the connection. The speed can be one of 9600, 19200,\n"
  891. L"38400, 57600 or 115200. for example, com1@115200 would connect using\n"
  892. L"the serial port com1, and a baud rate of 115.2K bps.\n");
  893. }