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.

1075 lines
23 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. pObject->m_Secret = uuidSerialPortObjectGuid;
  193. pObject->m_hPort = INVALID_HANDLE_VALUE;
  194. pObject->m_hAbort = NULL;
  195. pObject->m_hReadMutex = NULL; // Only one thread allowed to read a port
  196. pObject->m_hWriteMutex = NULL; // Only one thread allowed to read a port
  197. pObject->m_hCloseMutex = NULL; // Only one thread allowed to read a port
  198. pObject->m_hReadComplete = NULL; // Event to signal read completion
  199. pObject->m_hWriteComplete = NULL; // Event to signal write completion
  200. return pObject;
  201. }
  202. void lhcpDeleteObject(PSERIALPORT pObject)
  203. {
  204. if (pObject==NULL)
  205. {
  206. return;
  207. }
  208. ZeroMemory(
  209. &(pObject->m_Secret),
  210. sizeof(pObject->m_Secret));
  211. if (pObject->m_hPort!=INVALID_HANDLE_VALUE)
  212. {
  213. CloseHandle(
  214. pObject->m_hPort);
  215. }
  216. if (pObject->m_hAbort!=NULL)
  217. {
  218. CloseHandle(
  219. pObject->m_hAbort);
  220. }
  221. if (pObject->m_hReadMutex!=NULL)
  222. {
  223. CloseHandle(
  224. pObject->m_hReadMutex);
  225. }
  226. if (pObject->m_hWriteMutex!=NULL)
  227. {
  228. CloseHandle(
  229. pObject->m_hWriteMutex);
  230. }
  231. if (pObject->m_hCloseMutex!=NULL)
  232. {
  233. CloseHandle(
  234. pObject->m_hCloseMutex);
  235. }
  236. if (pObject->m_hReadComplete!=NULL)
  237. {
  238. CloseHandle(
  239. pObject->m_hReadComplete);
  240. }
  241. if (pObject->m_hWriteComplete!=NULL)
  242. {
  243. CloseHandle(
  244. pObject->m_hWriteComplete);
  245. }
  246. FillMemory(
  247. pObject,
  248. sizeof(SERIALPORT),
  249. 0x00);
  250. free(
  251. pObject);
  252. }
  253. BOOL lhcpParseParameters(PCWSTR pcszPortSpec, PWSTR* pszPort, PDWORD pdwBaudRate)
  254. {
  255. PWSTR pszSettings;
  256. *pszPort = malloc(
  257. (wcslen(pcszPortSpec) + 5) * sizeof(WCHAR));
  258. if (NULL==*pszPort)
  259. {
  260. SetLastError(
  261. ERROR_NOT_ENOUGH_MEMORY);
  262. goto Error;
  263. }
  264. wcscpy(
  265. *pszPort,
  266. L"\\\\.\\"); // Append the device prefix to the port name
  267. wcscat(
  268. *pszPort,
  269. pcszPortSpec);
  270. pszSettings = wcschr( // Find where the settings start
  271. *pszPort,
  272. L'@');
  273. if (NULL==pszSettings)
  274. {
  275. SetLastError(
  276. ERROR_INVALID_PARAMETER);
  277. goto Error;
  278. }
  279. *pszSettings++ = L'\0'; // Separate the strings
  280. *pdwBaudRate = 0;
  281. while (*pszSettings!=L'\0' && *pdwBaudRate<115200)
  282. {
  283. if (L'0'<=*pszSettings && *pszSettings<=L'9')
  284. {
  285. *pdwBaudRate *= 10;
  286. *pdwBaudRate += *pszSettings - L'0';
  287. pszSettings++;
  288. }
  289. else
  290. {
  291. break;
  292. }
  293. }
  294. if (*pszSettings!=L'0' && *pdwBaudRate!=9600 && *pdwBaudRate!=19200 &&
  295. *pdwBaudRate!=38400 && *pdwBaudRate!=57600 && *pdwBaudRate!=115200)
  296. {
  297. SetLastError(
  298. ERROR_INVALID_PARAMETER);
  299. goto Error;
  300. }
  301. return TRUE;
  302. Error:
  303. lhcpParseParametersFree(
  304. pszPort, pdwBaudRate);
  305. return FALSE;
  306. }
  307. void lhcpParseParametersFree(PWSTR* pszPort, PDWORD pdwBaudRate)
  308. {
  309. if (*pszPort != NULL)
  310. {
  311. free(*pszPort);
  312. *pszPort = NULL;
  313. }
  314. *pdwBaudRate = 0;
  315. }
  316. BOOL lhcpSetCommState(HANDLE hPort, DWORD dwBaudRate)
  317. {
  318. DCB MyDCB;
  319. COMMTIMEOUTS CommTimeouts;
  320. BOOL bResult;
  321. ZeroMemory(
  322. &MyDCB,
  323. sizeof(DCB));
  324. MyDCB.DCBlength = sizeof(DCB);
  325. MyDCB.BaudRate = dwBaudRate;
  326. MyDCB.fBinary = 1;
  327. MyDCB.fParity = 1;
  328. MyDCB.fOutxCtsFlow = 0;
  329. MyDCB.fOutxDsrFlow = 0;
  330. MyDCB.fDtrControl = 1;
  331. MyDCB.fDsrSensitivity = 0;
  332. MyDCB.fTXContinueOnXoff = 1;
  333. MyDCB.fOutX = 1;
  334. MyDCB.fInX = 1;
  335. MyDCB.fErrorChar = 0;
  336. MyDCB.fNull = 0;
  337. MyDCB.fRtsControl = 1;
  338. MyDCB.fAbortOnError = 0;
  339. MyDCB.XonLim = 0x50;
  340. MyDCB.XoffLim = 0xc8;
  341. MyDCB.ByteSize = 0x8;
  342. MyDCB.Parity = 0;
  343. MyDCB.StopBits = 0;
  344. MyDCB.XonChar = 17;
  345. MyDCB.XoffChar = 19;
  346. MyDCB.ErrorChar = 0;
  347. MyDCB.EofChar = 0;
  348. MyDCB.EvtChar = 0;
  349. bResult = SetCommState(
  350. hPort,
  351. &MyDCB);
  352. if (!bResult)
  353. {
  354. goto Error;
  355. }
  356. CommTimeouts.ReadIntervalTimeout = 0xffffffff; //MAXDWORD
  357. CommTimeouts.ReadTotalTimeoutMultiplier = 0x0; //MAXDWORD
  358. CommTimeouts.ReadTotalTimeoutConstant = 0x0;
  359. CommTimeouts.WriteTotalTimeoutMultiplier = 0;
  360. CommTimeouts.WriteTotalTimeoutConstant = 0;
  361. bResult = SetCommTimeouts(
  362. hPort,
  363. &CommTimeouts);
  364. if (!bResult)
  365. {
  366. goto Error;
  367. }
  368. bResult = SetCommMask(
  369. hPort,
  370. EV_SERIAL);
  371. if (!bResult)
  372. {
  373. goto Error;
  374. }
  375. return TRUE;
  376. Error:
  377. return FALSE;
  378. }
  379. BOOL lhcpWaitForCommEvent(PSERIALPORT pObject, PDWORD pdwEventMask)
  380. {
  381. OVERLAPPED Overlapped;
  382. BOOL bResult;
  383. HANDLE hWaiters[2];
  384. DWORD dwWaitResult;
  385. DWORD dwBytesTransferred;
  386. // I have no idea whether this is necessary, so I will do it just to be
  387. // on the safe side.
  388. ZeroMemory(
  389. &Overlapped,
  390. sizeof(OVERLAPPED));
  391. Overlapped.hEvent = pObject->m_hReadComplete;
  392. // Start waiting for a comm event
  393. bResult = WaitCommEvent(
  394. pObject->m_hPort,
  395. pdwEventMask,
  396. &Overlapped);
  397. if (!bResult && GetLastError()!=ERROR_IO_PENDING)
  398. {
  399. goto Error;
  400. }
  401. hWaiters[0] = pObject->m_hAbort;
  402. hWaiters[1] = pObject->m_hReadComplete;
  403. // Let's wait for the operation to complete. This will quit waiting if
  404. // the m_hAbort event is signalled.
  405. dwWaitResult = WaitForMultipleObjects(
  406. 2,
  407. hWaiters,
  408. FALSE,
  409. INFINITE);
  410. if (WAIT_OBJECT_0==dwWaitResult)
  411. {
  412. // The m_hAbort event was signalled. This means that Close was called
  413. // on this serial port object. So let's cancel the pending IO.
  414. CancelIo(
  415. pObject->m_hPort);
  416. // The serial port object is being closed, so let's call it invalid.
  417. SetLastError(
  418. ERROR_INVALID_HANDLE);
  419. goto Error;
  420. }
  421. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  422. {
  423. // This should never, ever happen - so I will put a debug breapoint
  424. // in here (checked only).
  425. #ifdef DBG
  426. DebugBreak();
  427. #endif
  428. goto Error;
  429. }
  430. // Check the success or failure of the operation
  431. bResult = GetOverlappedResult(
  432. pObject->m_hPort,
  433. &Overlapped,
  434. &dwBytesTransferred,
  435. TRUE);
  436. if (!bResult)
  437. {
  438. goto Error;
  439. }
  440. return TRUE;
  441. Error:
  442. return FALSE;
  443. }
  444. BOOL lhcpReadCommPort(
  445. PSERIALPORT pObject,
  446. PVOID pBuffer,
  447. DWORD dwSize,
  448. PDWORD pdwBytesRead)
  449. {
  450. OVERLAPPED Overlapped;
  451. BOOL bResult;
  452. DWORD dwWaitResult;
  453. HANDLE hWaiters[2];
  454. // I have no idea whether this is necessary, so I will do it just to be
  455. // on the safe side.
  456. ZeroMemory(
  457. &Overlapped,
  458. sizeof(OVERLAPPED));
  459. Overlapped.hEvent = pObject->m_hReadComplete;
  460. // We can now read the comm port
  461. bResult = ReadFile(
  462. pObject->m_hPort,
  463. pBuffer,
  464. dwSize,
  465. pdwBytesRead,
  466. &Overlapped);
  467. if (!bResult && GetLastError()!=ERROR_IO_PENDING)
  468. {
  469. goto Error;
  470. }
  471. hWaiters[0] = pObject->m_hAbort;
  472. hWaiters[1] = pObject->m_hReadComplete;
  473. // Let's wait for the operation to complete. This will quit waiting if
  474. // the m_hAbort event is signalled.
  475. dwWaitResult = WaitForMultipleObjects(
  476. 2,
  477. hWaiters,
  478. FALSE,
  479. INFINITE);
  480. if (WAIT_OBJECT_0==dwWaitResult)
  481. {
  482. // The m_hAbort event was signalled. This means that Close was called
  483. // on this serial port object. So let's cancel the pending IO.
  484. CancelIo(
  485. pObject->m_hPort);
  486. // The serial port object is being closed, so let's call it invalid.
  487. SetLastError(
  488. ERROR_INVALID_HANDLE);
  489. goto Error;
  490. }
  491. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  492. {
  493. // This should never, ever happen - so I will put a debug breapoint
  494. // in here (checked only).
  495. #ifdef DBG
  496. DebugBreak();
  497. #endif
  498. goto Error;
  499. }
  500. // Check the success or failure of the read operation
  501. bResult = GetOverlappedResult(
  502. pObject->m_hPort,
  503. &Overlapped,
  504. pdwBytesRead,
  505. TRUE);
  506. if (!bResult)
  507. {
  508. goto Error;
  509. }
  510. return TRUE;
  511. Error:
  512. return FALSE;
  513. }
  514. BOOL lhcpWriteCommPort(
  515. PSERIALPORT pObject,
  516. PVOID pBuffer,
  517. DWORD dwSize)
  518. {
  519. OVERLAPPED Overlapped;
  520. BOOL bResult;
  521. DWORD dwBytesWritten;
  522. DWORD dwWaitResult;
  523. HANDLE hWaiters[2];
  524. // I have no idea whether this is necessary, so I will do it just to be
  525. // on the safe side.
  526. ZeroMemory(
  527. &Overlapped,
  528. sizeof(OVERLAPPED));
  529. Overlapped.hEvent = pObject->m_hWriteComplete;
  530. // We can now read the comm port
  531. bResult = WriteFile(
  532. pObject->m_hPort,
  533. pBuffer,
  534. dwSize,
  535. &dwBytesWritten,
  536. &Overlapped);
  537. if (!bResult && GetLastError()!=ERROR_IO_PENDING)
  538. {
  539. goto Error;
  540. }
  541. hWaiters[0] = pObject->m_hAbort;
  542. hWaiters[1] = pObject->m_hWriteComplete;
  543. // Let's wait for the operation to complete. This will quit waiting if
  544. // the m_hAbort event is signalled. If the read operation completed
  545. // immediately, then this wait will succeed immediately.
  546. dwWaitResult = WaitForMultipleObjects(
  547. 2,
  548. hWaiters,
  549. FALSE,
  550. INFINITE);
  551. if (WAIT_OBJECT_0==dwWaitResult)
  552. {
  553. // The m_hAbort event was signalled. This means that Close was called
  554. // on this serial port object. So let's cancel the pending IO.
  555. CancelIo(
  556. pObject->m_hPort);
  557. // The serial port object is being closed, so let's call it invalid.
  558. SetLastError(
  559. ERROR_INVALID_HANDLE);
  560. goto Error;
  561. }
  562. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  563. {
  564. // This should never, ever happen - so I will put a debug breapoint
  565. // in here (checked only).
  566. #ifdef DBG
  567. DebugBreak();
  568. #endif
  569. goto Error;
  570. }
  571. // Check the success or failure of the write operation
  572. bResult = GetOverlappedResult(
  573. pObject->m_hPort,
  574. &Overlapped,
  575. &dwBytesWritten,
  576. TRUE);
  577. if (!bResult)
  578. {
  579. goto Error;
  580. }
  581. return TRUE;
  582. Error:
  583. return FALSE;
  584. }
  585. extern PVOID APIENTRY lhcOpen(PCWSTR pcszPortSpec)
  586. {
  587. BOOL bResult;
  588. PWSTR pszPort;
  589. DWORD dwBaudRate;
  590. PSERIALPORT pObject = NULL;
  591. DCB MyDCB;
  592. bResult = lhcpParseParameters(
  593. pcszPortSpec,
  594. &pszPort,
  595. &dwBaudRate);
  596. if (!bResult)
  597. {
  598. goto Error;
  599. }
  600. // Allocate space and initialize the serial port object
  601. pObject = lhcpCreateNewObject();
  602. if (NULL==pObject)
  603. {
  604. goto Error;
  605. }
  606. // Open the serial port
  607. pObject->m_hPort = CreateFileW(
  608. pszPort,
  609. GENERIC_ALL,
  610. 0,
  611. NULL,
  612. OPEN_EXISTING,
  613. FILE_FLAG_OVERLAPPED,
  614. NULL);
  615. if (INVALID_HANDLE_VALUE==pObject->m_hPort)
  616. {
  617. goto Error;
  618. }
  619. // Set the properties of the serial port
  620. bResult = lhcpSetCommState(
  621. pObject->m_hPort,
  622. dwBaudRate);
  623. if (!bResult)
  624. {
  625. goto Error;
  626. }
  627. // This event will be set when we want to close the port
  628. pObject->m_hAbort = CreateEvent(
  629. NULL,
  630. TRUE,
  631. FALSE,
  632. NULL);
  633. if (NULL==pObject->m_hAbort)
  634. {
  635. goto Error;
  636. }
  637. // This event will be used for overlapped reading from the port
  638. pObject->m_hReadComplete = CreateEvent(
  639. NULL,
  640. TRUE,
  641. FALSE,
  642. NULL);
  643. if (NULL==pObject->m_hReadComplete)
  644. {
  645. goto Error;
  646. }
  647. // This event will be used for overlapped writing to the port
  648. pObject->m_hWriteComplete = CreateEvent(
  649. NULL,
  650. TRUE,
  651. FALSE,
  652. NULL);
  653. if (NULL==pObject->m_hWriteComplete)
  654. {
  655. goto Error;
  656. }
  657. // This mutex will ensure that only one thread can read at a time
  658. pObject->m_hReadMutex = CreateMutex(
  659. NULL,
  660. FALSE,
  661. NULL);
  662. if (NULL==pObject->m_hReadMutex)
  663. {
  664. goto Error;
  665. }
  666. // This mutex will ensure that only one thread can write at a time
  667. pObject->m_hWriteMutex = CreateMutex(
  668. NULL,
  669. FALSE,
  670. NULL);
  671. if (NULL==pObject->m_hWriteMutex)
  672. {
  673. goto Error;
  674. }
  675. // This mutex will ensure that only one thread can close the port
  676. pObject->m_hCloseMutex = CreateMutex(
  677. NULL,
  678. FALSE,
  679. NULL);
  680. if (NULL==pObject->m_hCloseMutex)
  681. {
  682. goto Error;
  683. }
  684. // Free up the temporary memory used to parse the parameters
  685. lhcpParseParametersFree(
  686. &pszPort, &dwBaudRate);
  687. // Return a pointer to the new object
  688. return pObject;
  689. Error:
  690. lhcpParseParametersFree(
  691. &pszPort, &dwBaudRate);
  692. lhcpDeleteObject(
  693. pObject);
  694. return NULL;
  695. }
  696. extern BOOL APIENTRY lhcRead(
  697. PVOID pObject,
  698. PVOID pBuffer,
  699. DWORD dwSize,
  700. PDWORD pdwBytesRead)
  701. {
  702. OVERLAPPED Overlapped;
  703. DWORD dwEventMask;
  704. BOOL bResult;
  705. // Firstly, we need to check whether the pointer that got passed in
  706. // points to a valid SERIALPORT object
  707. if (!lhcpIsValidObject(pObject))
  708. {
  709. goto NoMutex;
  710. }
  711. bResult = lhcpAcquireReadWithAbort(
  712. (PSERIALPORT)pObject);
  713. if (!bResult)
  714. {
  715. SetLastError(
  716. ERROR_INVALID_HANDLE);
  717. goto NoMutex;
  718. }
  719. // Wait for something to happen to the serial port
  720. bResult = lhcpWaitForCommEvent(
  721. (PSERIALPORT)pObject, &dwEventMask);
  722. if (!bResult)
  723. {
  724. goto Error;
  725. }
  726. // We should now have a valid serial port event, so let's read the port.
  727. bResult = lhcpReadCommPort(
  728. (PSERIALPORT)pObject,
  729. pBuffer,
  730. dwSize,
  731. pdwBytesRead);
  732. if (!bResult)
  733. {
  734. goto Error;
  735. }
  736. lhcpReleaseRead(
  737. (PSERIALPORT)pObject);
  738. return TRUE;
  739. Error:
  740. lhcpReleaseRead(
  741. (PSERIALPORT)pObject);
  742. NoMutex:
  743. return FALSE;
  744. }
  745. extern BOOL APIENTRY lhcWrite(
  746. PVOID pObject,
  747. PVOID pBuffer,
  748. DWORD dwSize)
  749. {
  750. OVERLAPPED Overlapped;
  751. BOOL bResult;
  752. // Firstly, we need to check whether the pointer that got passed in
  753. // points to a valid SERIALPORT object
  754. if (!lhcpIsValidObject(pObject))
  755. {
  756. goto NoMutex;
  757. }
  758. // Block until it is your turn
  759. bResult = lhcpAcquireWriteWithAbort(
  760. pObject);
  761. if (!bResult)
  762. {
  763. SetLastError(
  764. ERROR_INVALID_HANDLE);
  765. goto NoMutex;
  766. }
  767. // Wait for something to happen to the serial port
  768. bResult = lhcpWriteCommPort(
  769. (PSERIALPORT)pObject,
  770. pBuffer,
  771. dwSize);
  772. if (!bResult)
  773. {
  774. goto Error;
  775. }
  776. lhcpReleaseWrite(
  777. (PSERIALPORT)pObject);
  778. return TRUE;
  779. Error:
  780. lhcpReleaseWrite(
  781. (PSERIALPORT)pObject);
  782. NoMutex:
  783. return FALSE;
  784. }
  785. extern BOOL APIENTRY lhcClose(PVOID pObject)
  786. {
  787. BOOL bResult;
  788. // Firstly, we need to check whether the pointer that got passed in
  789. // points to a valid SERIALPORT object
  790. if (!lhcpIsValidObject(pObject))
  791. {
  792. goto Error;
  793. }
  794. // We need to ensure that we are the only thread closing this object
  795. bResult = lhcpAcquireCloseWithAbort(
  796. pObject);
  797. if (!bResult)
  798. {
  799. SetLastError(
  800. ERROR_INVALID_HANDLE);
  801. goto NoMutex;
  802. }
  803. // Signal everyone to quit doing what they're doing. Any new threads
  804. // calling lhcRead and lhcWrite will be immediately sent packing, since
  805. // the m_hAbort event is waited on along with the relevant mutex.
  806. bResult = SetEvent(
  807. ((PSERIALPORT)pObject)->m_hAbort);
  808. if (!bResult)
  809. {
  810. goto Error;
  811. }
  812. // Now acquire the read and write mutexes so that no-one else will try to
  813. // access this object to read or write. Abort does not apply, since we
  814. // have already signalled it. We know that we are closing, and we need
  815. // the read and write mutexes.
  816. bResult = lhcpAcquireReadAndWrite(
  817. (PSERIALPORT)pObject);
  818. if (!bResult)
  819. {
  820. SetLastError(
  821. ERROR_INVALID_HANDLE);
  822. goto Error;
  823. }
  824. // Closes all of the open handles, erases the secret and frees up the
  825. // memory associated with the object. We can close the mutex objects,
  826. // even though we are the owners, since we can guarantee that no-one
  827. // else is waiting on them. The m_hAbort event being signalled will
  828. // ensure this.
  829. lhcpDeleteObject(
  830. (PSERIALPORT)pObject);
  831. return TRUE;
  832. Error:
  833. lhcpReleaseClose(
  834. (PSERIALPORT)pObject);
  835. NoMutex:
  836. return FALSE;
  837. }
  838. extern DWORD APIENTRY lhcGetLibraryName(
  839. PWSTR pszBuffer,
  840. DWORD dwSize)
  841. {
  842. DWORD dwNameSize = wcslen(SERIALPORT_NAME)+1;
  843. // If zero is passed in as the buffer length, we will return the
  844. // required buffer size in characters, as calulated above. If the
  845. // incoming buffer size is not zero, and smaller than the required
  846. // buffer size, we return 0 (failure) with a valid error code. Notice
  847. // that in the case where the incoming size is zero, we don't touch
  848. // the buffer pointer at all.
  849. if (dwSize!=0 && dwSize < dwNameSize)
  850. {
  851. SetLastError(
  852. ERROR_INSUFFICIENT_BUFFER);
  853. dwNameSize = 0;
  854. }
  855. else
  856. {
  857. wcscpy(
  858. pszBuffer,
  859. SERIALPORT_NAME);
  860. }
  861. return dwNameSize;
  862. }