[KERNEL32_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / kernel32 / comm.c
1 /* Unit test suite for comm functions
2 *
3 * Copyright 2003 Kevin Groeneveld
4 * Copyright 2005 Uwe Bonnes
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #define TIMEOUT 1000 /* one second for Timeouts*/
24 #define SLOWBAUD 150
25 #define FASTBAUD 115200
26 #define TIMEDELTA 150 /* 150 ms uncertainty allowed */
27
28 /* Define the appropriate LOOPBACK(s) TRUE if you have a Loopback cable with
29 * the mentioned shorts connected to your Serial port
30 */
31 #define LOOPBACK_TXD_RXD FALSE /* Sub-D 9: Short 2-3 */
32 #define LOOPBACK_CTS_RTS FALSE /* Sub-D 9: Short 7-8 */
33 #define LOOPBACK_DTR_DSR FALSE /* Sub-D 9: Short 4-6 */
34 #define LOOPBACK_DTR_RING FALSE /* Sub-D 9: Short 4-9 */
35 #define LOOPBACK_DTR_DCD FALSE /* Sub-D 9: Short 4-1 */
36 /* Many Linux serial drivers have the TIOCM_LOOP flag in the TIOCM_SET ioctl
37 * available. For the 8250 this is equivalent to TXD->RXD, OUT2->DCD,
38 * OUT1->RI, RTS->CTS and DTR->DSR
39 */
40 /* use variables and not #define to compile the code */
41 static BOOL loopback_txd_rxd = LOOPBACK_TXD_RXD;
42 static BOOL loopback_rts_cts = LOOPBACK_CTS_RTS;
43 static BOOL loopback_dtr_dsr = LOOPBACK_DTR_DSR;
44 static BOOL loopback_dtr_ring = LOOPBACK_DTR_RING;
45 static BOOL loopback_dtr_dcd = LOOPBACK_DTR_DCD;
46
47 static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent,
48 PIO_APC_ROUTINE apc, void* apc_user,
49 PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
50 PLARGE_INTEGER offset, PULONG key);
51 static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
52 PIO_APC_ROUTINE apc, void* apc_user,
53 PIO_STATUS_BLOCK io_status,
54 const void* buffer, ULONG length,
55 PLARGE_INTEGER offset, PULONG key);
56
57 typedef struct
58 {
59 char string[100];
60 BOOL result;
61 BOOL old_style;
62 DCB dcb1, dcb2;
63 COMMTIMEOUTS timeouts1, timeouts2;
64 } TEST;
65
66 static const TEST test[] =
67 {
68 {
69 "baud=9600 parity=e data=5 stop=1 xon=on odsr=off octs=off dtr=on rts=on idsr=on",
70 TRUE, FALSE,
71 { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
72 { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
73 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
74 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
75 },
76 {
77 "baud=0 parity=M data=6 stop=1.5 xon=off odsr=on octs=ON dtr=off rts=off idsr=OFF",
78 TRUE, FALSE,
79 { 0x00000000, 0x00000000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
80 { 0xffffffff, 0x00000000, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
81 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
82 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
83 },
84 {
85 "BAUD=4000000000 parity=n data=7 stop=2 to=off",
86 TRUE, FALSE,
87 { 0x00000000, 0xee6b2800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
88 { 0xffffffff, 0xee6b2800, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
89 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
90 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
91 },
92 {
93 "Baud=115200 Parity=O Data=8 To=On",
94 TRUE, FALSE,
95 { 0x00000000, 0x0001c200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
96 { 0xffffffff, 0x0001c200, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
97 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 },
98 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 }
99 },
100 {
101 "PaRiTy=s Data=7 DTR=on",
102 TRUE, FALSE,
103 { 0x00000000, 0x00000000, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
104 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
105 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
106 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
107 },
108 {
109 "data=4",
110 FALSE, FALSE,
111 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
112 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
113 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
114 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
115 },
116 {
117 "data=9",
118 FALSE, FALSE,
119 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
120 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
121 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
122 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
123 },
124 {
125 "parity=no",
126 FALSE, FALSE,
127 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
128 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
129 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
130 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
131 },
132 {
133 "stop=0",
134 FALSE, FALSE,
135 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
136 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
137 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
138 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
139 },
140 {
141 "stop=1.501",
142 FALSE, FALSE,
143 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
144 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
145 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
146 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
147 },
148 {
149 "stop=3",
150 FALSE, FALSE,
151 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
152 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
153 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
154 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
155 },
156 {
157 "to=foobar",
158 FALSE, FALSE,
159 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
160 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
161 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
162 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
163 },
164 {
165 " baud=9600",
166 FALSE, FALSE,
167 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
168 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
169 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
170 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
171 },
172 {
173 "baud= 9600",
174 FALSE, FALSE,
175 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
176 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
177 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
178 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
179 },
180 {
181 "baud=9600,data=8",
182 FALSE, FALSE,
183 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
184 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
185 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
186 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
187 },
188 {
189 "11,n,8,1",
190 TRUE, TRUE,
191 { 0x00000000, 0x0000006e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
192 { 0xffffffff, 0x0000006e, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
193 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
194 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
195 },
196 {
197 "30 ,E, 5,1.5",
198 TRUE, TRUE,
199 { 0x00000000, 0x0000012c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
200 { 0xffffffff, 0x0000012c, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x02, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
201 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
202 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
203 },
204 {
205 "60, m, 6, 2 ",
206 TRUE, TRUE,
207 { 0x00000000, 0x00000258, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
208 { 0xffffffff, 0x00000258, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
209 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
210 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
211 },
212 {
213 "12 , o , 7 , 1",
214 TRUE, TRUE,
215 { 0x00000000, 0x000004b0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
216 { 0xffffffff, 0x000004b0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
217 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
218 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
219 },
220 {
221 "24,s,8,1.5",
222 TRUE, TRUE,
223 { 0x00000000, 0x00000960, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
224 { 0xffffffff, 0x00000960, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x04, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
225 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
226 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
227 },
228 {
229 "48,n,8,1,p",
230 TRUE, TRUE,
231 { 0x00000000, 0x000012c0, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
232 { 0xffffffff, 0x000012c0, 1, 1, 1, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
233 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
234 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
235 },
236 {
237 "96,N,8,1 , x ",
238 TRUE, TRUE,
239 { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
240 { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
241 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
242 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
243 },
244 {
245 "19, e, 7, 1, x",
246 TRUE, TRUE,
247 { 0x00000000, 0x00004b00, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
248 { 0xffffffff, 0x00004b00, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
249 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
250 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
251 },
252 {
253 "0,M,7,1,P",
254 TRUE, TRUE,
255 { 0x00000000, 0x00000000, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
256 { 0xffffffff, 0x00000000, 1, 1, 1, 1, 2, 1, 1, 0, 0, 1, 1, 2, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
257 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
258 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
259 },
260 {
261 "4000000000,O,7,1.5,X",
262 TRUE, TRUE,
263 { 0x00000000, 0xee6b2800, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
264 { 0xffffffff, 0xee6b2800, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
265 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
266 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
267 },
268 {
269 "96,N,8,1 to=on",
270 FALSE, TRUE,
271 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
272 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
273 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
274 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
275 },
276 {
277 "96,NO,8,1",
278 FALSE, TRUE,
279 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
280 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
281 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
282 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
283 },
284 {
285 "96,N,4,1",
286 FALSE, TRUE,
287 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
288 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
289 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
290 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
291 },
292 {
293 "96,N,9,1",
294 FALSE, TRUE,
295 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
296 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
297 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
298 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
299 },
300 {
301 "96,N,8,0",
302 FALSE, TRUE,
303 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
304 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
305 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
306 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
307 },
308 {
309 "96,N,8,3",
310 FALSE, TRUE,
311 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
312 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
313 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
314 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
315 },
316 {
317 "96,N,8,1,K",
318 FALSE, TRUE,
319 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
320 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
321 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
322 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
323 },
324 {
325 "COM0:baud=115200",
326 FALSE, FALSE,
327 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
328 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
329 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
330 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
331 },
332 {
333 "COMx:baud=38400 data=8",
334 TRUE, FALSE,
335 { 0x00000000, 0x00009600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
336 { 0xffffffff, 0x00009600, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
337 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
338 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
339 },
340 {
341 "COMx :to=on stop=1.5",
342 TRUE, FALSE,
343 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
344 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
345 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 },
346 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000EA60 }
347 },
348 {
349 "COMx: baud=12345 data=7",
350 TRUE, FALSE,
351 { 0x00000000, 0x00003039, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
352 { 0xffffffff, 0x00003039, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
353 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
354 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
355 },
356 {
357 "COMx : xon=on odsr=off",
358 TRUE, FALSE,
359 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
360 { 0xffffffff, 0xffffffff, 1, 1, 1, 0, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
361 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
362 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
363 },
364 {
365 "COM0:9600,N,8,1",
366 FALSE, TRUE,
367 { 0x00000000, 0x00000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
368 { 0xffffffff, 0xffffffff, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
369 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
370 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
371 },
372 {
373 "COMx:9600,N,8,1",
374 TRUE, TRUE,
375 { 0x00000000, 0x00002580, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
376 { 0xffffffff, 0x00002580, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x08, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
377 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
378 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
379 },
380 {
381 "COMx: 11,E,7,2",
382 TRUE, TRUE,
383 { 0x00000000, 0x0000006e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x07, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
384 { 0xffffffff, 0x0000006e, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x07, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
385 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
386 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
387 },
388 {
389 "COMx :19,M,5,1",
390 TRUE, TRUE,
391 { 0x00000000, 0x00004b00, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
392 { 0xffffffff, 0x00004b00, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x05, 0x03, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
393 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
394 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
395 },
396 {
397 "COMx : 57600,S,6,2,x",
398 TRUE, TRUE,
399 { 0x00000000, 0x0000e100, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0x00000, 0x0000, 0x0000, 0x0000, 0x06, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0000 },
400 { 0xffffffff, 0x0000e100, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x1ffff, 0xffff, 0xffff, 0xffff, 0x06, 0x04, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffff },
401 { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
402 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
403 },
404 };
405
406 #define TEST_COUNT (sizeof(test) / sizeof(TEST))
407
408 /* This function can be useful if you are modifying the test cases and want to
409 output the contents of a DCB structure. */
410 /*static print_dcb(DCB *pdcb)
411 {
412 printf("0x%08x, 0x%08x, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, 0x%05x, 0x%04x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%04x\n",
413 pdcb->DCBlength,
414 pdcb->BaudRate,
415 pdcb->fBinary,
416 pdcb->fParity,
417 pdcb->fOutxCtsFlow,
418 pdcb->fOutxDsrFlow,
419 pdcb->fDtrControl,
420 pdcb->fDsrSensitivity,
421 pdcb->fTXContinueOnXoff,
422 pdcb->fOutX,
423 pdcb->fInX,
424 pdcb->fErrorChar,
425 pdcb->fNull,
426 pdcb->fRtsControl,
427 pdcb->fAbortOnError,
428 pdcb->fDummy2,
429 pdcb->wReserved,
430 pdcb->XonLim,
431 pdcb->XoffLim,
432 pdcb->ByteSize,
433 pdcb->Parity,
434 pdcb->StopBits,
435 pdcb->XonChar & 0xff,
436 pdcb->XoffChar & 0xff,
437 pdcb->ErrorChar & 0xff,
438 pdcb->EofChar & 0xff,
439 pdcb->EvtChar & 0xff,
440 pdcb->wReserved1 & 0xffff );
441 } */
442
443 static void check_result(const char *function, const TEST *ptest, int initial_value, BOOL result)
444 {
445 DWORD LastError = GetLastError();
446 DWORD CorrectError = (ptest->result ? 0xdeadbeef : ERROR_INVALID_PARAMETER);
447
448 ok(LastError == CorrectError, "%s(\"%s\"), 0x%02x: GetLastError() returned %d, should be %d\n", function, ptest->string, initial_value, LastError, CorrectError);
449 ok(result == ptest->result, "%s(\"%s\"), 0x%02x: return value should be %s\n", function, ptest->string, initial_value, ptest->result ? "TRUE" : "FALSE");
450 }
451
452 #define check_dcb_member(a,b) ok(pdcb1->a == pdcb2->a, "%s(\"%s\"), 0x%02x: "#a" is "b", should be "b"\n", function, ptest->string, initial_value, pdcb1->a, pdcb2->a)
453 #define check_dcb_member2(a,c,b) if(pdcb2->a == c) { check_dcb_member(a,b); } else { ok(pdcb1->a == pdcb2->a || pdcb1->a == c, "%s(\"%s\"), 0x%02x: "#a" is "b", should be "b" or "b"\n", function, ptest->string, initial_value, pdcb1->a, pdcb2->a, c); }
454
455 static void check_dcb(const char *function, const TEST *ptest, int initial_value, const DCB *pdcb1, const DCB *pdcb2)
456 {
457 /* DCBlength is a special case since Win 9x sets it but NT does not.
458 We will accept either as correct. */
459 check_dcb_member2(DCBlength, (DWORD)sizeof(DCB), "%u");
460
461 /* For old style control strings Win 9x does not set the next five members, NT does. */
462 if(ptest->old_style && ptest->result)
463 {
464 check_dcb_member2(fOutxCtsFlow, ((unsigned int)initial_value & 1), "%u");
465 check_dcb_member2(fDtrControl, ((unsigned int)initial_value & 3), "%u");
466 check_dcb_member2(fOutX, ((unsigned int)initial_value & 1), "%u");
467 check_dcb_member2(fInX, ((unsigned)initial_value & 1), "%u");
468 check_dcb_member2(fRtsControl, ((unsigned)initial_value & 3), "%u");
469 }
470 else
471 {
472 check_dcb_member(fOutxCtsFlow, "%u");
473 check_dcb_member(fDtrControl, "%u");
474 check_dcb_member(fOutX, "%u");
475 check_dcb_member(fInX, "%u");
476 check_dcb_member(fRtsControl, "%u");
477 }
478
479 if(ptest->result)
480 {
481 /* For the idsr=xxx parameter, NT sets fDsrSensitivity, 9x sets
482 fOutxDsrFlow. */
483 if(!ptest->old_style)
484 {
485 check_dcb_member2(fOutxDsrFlow, pdcb2->fDsrSensitivity, "%u");
486 check_dcb_member2(fDsrSensitivity, pdcb2->fOutxDsrFlow, "%u");
487 }
488 else
489 {
490 /* For old style control strings Win 9x does not set the
491 fOutxDsrFlow member, NT does. */
492 check_dcb_member2(fOutxDsrFlow, ((unsigned int)initial_value & 1), "%u");
493 check_dcb_member(fDsrSensitivity, "%u");
494 }
495 }
496 else
497 {
498 check_dcb_member(fOutxDsrFlow, "%u");
499 check_dcb_member(fDsrSensitivity, "%u");
500 }
501
502 /* Check the result of the DCB members. */
503 check_dcb_member(BaudRate, "%u");
504 check_dcb_member(fBinary, "%u");
505 check_dcb_member(fParity, "%u");
506 check_dcb_member(fTXContinueOnXoff, "%u");
507 check_dcb_member(fErrorChar, "%u");
508 check_dcb_member(fNull, "%u");
509 check_dcb_member(fAbortOnError, "%u");
510 check_dcb_member(fDummy2, "%u");
511 check_dcb_member(wReserved, "%u");
512 check_dcb_member(XonLim, "%u");
513 check_dcb_member(XoffLim, "%u");
514 check_dcb_member(ByteSize, "%u");
515 check_dcb_member(Parity, "%u");
516 check_dcb_member(StopBits, "%u");
517 check_dcb_member(XonChar, "%d");
518 check_dcb_member(XoffChar, "%d");
519 check_dcb_member(ErrorChar, "%d");
520 check_dcb_member(EofChar, "%d");
521 check_dcb_member(EvtChar, "%d");
522 check_dcb_member(wReserved1, "%u");
523 }
524
525 #define check_timeouts_member(a) ok(ptimeouts1->a == ptimeouts2->a, "%s(\"%s\"), 0x%02x: "#a" is %u, should be %u\n", function, ptest->string, initial_value, ptimeouts1->a, ptimeouts2->a);
526
527 static void check_timeouts(const char *function, const TEST *ptest, int initial_value, const COMMTIMEOUTS *ptimeouts1, const COMMTIMEOUTS *ptimeouts2)
528 {
529 check_timeouts_member(ReadIntervalTimeout);
530 check_timeouts_member(ReadTotalTimeoutMultiplier);
531 check_timeouts_member(ReadTotalTimeoutConstant);
532 check_timeouts_member(WriteTotalTimeoutMultiplier);
533 check_timeouts_member(WriteTotalTimeoutConstant);
534 }
535
536 static void test_BuildCommDCBA(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb)
537 {
538 BOOL result;
539 DCB dcb;
540
541 /* set initial conditions */
542 memset(&dcb, initial_value, sizeof(DCB));
543 SetLastError(0xdeadbeef);
544
545 result = BuildCommDCBA(string, &dcb);
546
547 /* check results */
548 check_result("BuildCommDCBA", ptest, initial_value, result);
549 check_dcb("BuildCommDCBA", ptest, initial_value, &dcb, pexpected_dcb);
550 }
551
552 static void test_BuildCommDCBAndTimeoutsA(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb, const COMMTIMEOUTS *pexpected_timeouts)
553 {
554 BOOL result;
555 DCB dcb;
556 COMMTIMEOUTS timeouts;
557
558 /* set initial conditions */
559 memset(&dcb, initial_value, sizeof(DCB));
560 memset(&timeouts, initial_value, sizeof(COMMTIMEOUTS));
561 SetLastError(0xdeadbeef);
562
563 result = BuildCommDCBAndTimeoutsA(string, &dcb, &timeouts);
564
565 /* check results */
566 check_result("BuildCommDCBAndTimeoutsA", ptest, initial_value, result);
567 check_dcb("BuildCommDCBAndTimeoutsA", ptest, initial_value, &dcb, pexpected_dcb);
568 check_timeouts("BuildCommDCBAndTimeoutsA", ptest, initial_value, &timeouts, pexpected_timeouts);
569 }
570
571 static void test_BuildCommDCBW(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb)
572 {
573 BOOL result;
574 DCB dcb;
575 WCHAR wide_string[sizeof(ptest->string)];
576 static int reportedDCBW = 0;
577
578 MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR));
579
580 /* set initial conditions */
581 memset(&dcb, initial_value, sizeof(DCB));
582 SetLastError(0xdeadbeef);
583
584 result = BuildCommDCBW(wide_string, &dcb);
585
586 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
587 {
588 if(!reportedDCBW++)
589 win_skip("BuildCommDCBW is not implemented\n");
590 return;
591 }
592
593 /* check results */
594 check_result("BuildCommDCBW", ptest, initial_value, result);
595 check_dcb("BuildCommDCBW", ptest, initial_value, &dcb, pexpected_dcb);
596 }
597
598 static void test_BuildCommDCBAndTimeoutsW(const char *string, const TEST *ptest, int initial_value, const DCB *pexpected_dcb, const COMMTIMEOUTS *pexpected_timeouts)
599 {
600 BOOL result;
601 DCB dcb;
602 COMMTIMEOUTS timeouts;
603 WCHAR wide_string[sizeof(ptest->string)];
604 static int reportedDCBAndTW = 0;
605
606 MultiByteToWideChar(CP_ACP, 0, string, -1, wide_string, sizeof(wide_string) / sizeof(WCHAR));
607
608 /* set initial conditions */
609 memset(&dcb, initial_value, sizeof(DCB));
610 memset(&timeouts, initial_value, sizeof(COMMTIMEOUTS));
611 SetLastError(0xdeadbeef);
612
613 result = BuildCommDCBAndTimeoutsW(wide_string, &dcb, &timeouts);
614
615 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
616 {
617 if(!reportedDCBAndTW++)
618 win_skip("BuildCommDCBAndTimeoutsW is not implemented\n");
619 return;
620 }
621
622 /* check results */
623 check_result("BuildCommDCBAndTimeoutsW", ptest, initial_value, result);
624 check_dcb("BuildCommDCBAndTimeoutsW", ptest, initial_value, &dcb, pexpected_dcb);
625 check_timeouts("BuildCommDCBAndTimeoutsW", ptest, initial_value, &timeouts, pexpected_timeouts);
626 }
627
628 static void test_BuildCommDCB(void)
629 {
630 char port_name[] = "COMx";
631 char port = 0;
632 unsigned int i;
633 char *ptr;
634
635 /* Some of these tests require a valid COM port. This loop will try to find
636 a valid port. */
637 for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
638 {
639 COMMCONFIG commconfig;
640 DWORD size = sizeof(COMMCONFIG);
641
642 if(GetDefaultCommConfigA(port_name, &commconfig, &size))
643 {
644 port = port_name[3];
645 break;
646 }
647 }
648
649 if(!port)
650 trace("Could not find a valid COM port. Some tests will be skipped.\n");
651
652 for(i = 0; i < TEST_COUNT; i++)
653 {
654 char string[sizeof(test[i].string)];
655
656 strcpy(string, test[i].string);
657
658 /* Check if this test case needs a valid COM port. */
659 ptr = strstr(string, "COMx");
660
661 /* If required, substitute valid port number into device control string. */
662 if(ptr)
663 {
664 if(port)
665 ptr[3] = port;
666 else
667 continue;
668 }
669
670 test_BuildCommDCBA(string, &test[i], 0x00, &test[i].dcb1);
671 test_BuildCommDCBA(string, &test[i], 0xff, &test[i].dcb2);
672 test_BuildCommDCBAndTimeoutsA(string, &test[i], 0x00, &test[i].dcb1, &test[i].timeouts1);
673 test_BuildCommDCBAndTimeoutsA(string, &test[i], 0xff, &test[i].dcb2, &test[i].timeouts2);
674
675 test_BuildCommDCBW(string, &test[i], 0x00, &test[i].dcb1);
676 test_BuildCommDCBW(string, &test[i], 0xff, &test[i].dcb2);
677 test_BuildCommDCBAndTimeoutsW(string, &test[i], 0x00, &test[i].dcb1, &test[i].timeouts1);
678 test_BuildCommDCBAndTimeoutsW(string, &test[i], 0xff, &test[i].dcb2, &test[i].timeouts2);
679 }
680 }
681
682 static HANDLE test_OpenComm(BOOL doOverlap)
683 {
684 HANDLE hcom = INVALID_HANDLE_VALUE;
685 char port_name[] = "COMx";
686 static BOOL shown = FALSE;
687 DWORD errors;
688 COMSTAT comstat;
689
690 /* Try to find a port */
691 for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
692 {
693 hcom = CreateFileA( port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
694 (doOverlap)?FILE_FLAG_OVERLAPPED:0, NULL );
695 if (hcom != INVALID_HANDLE_VALUE)
696 break;
697 }
698 if(!shown)
699 {
700 if (hcom == INVALID_HANDLE_VALUE)
701 trace("Could not find a valid COM port.\n");
702 else
703 trace("Found Com port %s. Connected devices may disturb results\n", port_name);
704 /*shown = TRUE; */
705 }
706 if (hcom != INVALID_HANDLE_VALUE)
707 {
708 BOOL ret;
709
710 ret = ClearCommError(hcom, &errors, &comstat);
711 if (!ret && (GetLastError() == ERROR_NOT_READY || GetLastError() == ERROR_INVALID_HANDLE))
712 {
713 if (GetLastError() == ERROR_NOT_READY)
714 trace("%s doesn't respond, skipping the test\n", port_name);
715 else
716 trace("%s is not a real serial port, skipping the test\n", port_name);
717 CloseHandle(hcom);
718 return INVALID_HANDLE_VALUE;
719 }
720
721 ok(ret, "Unexpected error %u on open\n", GetLastError());
722 ok(comstat.cbInQue == 0, "Unexpected %d chars in InQueue\n",comstat.cbInQue);
723 ok(comstat.cbOutQue == 0, "Still pending %d charcters in OutQueue\n", comstat.cbOutQue);
724 ok(errors == 0, "Unexpected errors 0x%08x\n", errors);
725 }
726 return hcom;
727 }
728
729 static void test_GetModemStatus(HANDLE hcom)
730 {
731 DWORD ModemStat = 0;
732
733 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
734 trace("GetCommModemStatus returned 0x%08x->%s%s%s%s\n", ModemStat,
735 (ModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
736 (ModemStat &MS_RING_ON)?"MS_RING_ON ":"",
737 (ModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
738 (ModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
739 }
740
741 /* When we don't write anything, Read should time out even on a loopbacked port */
742 static void test_ReadTimeOut(void)
743 {
744 HANDLE hcom;
745 DCB dcb;
746 COMMTIMEOUTS timeouts;
747 char rbuf[32];
748 DWORD before, after, read, timediff, LastError;
749 BOOL res;
750
751 hcom = test_OpenComm(FALSE);
752 if (hcom == INVALID_HANDLE_VALUE) return;
753
754 test_GetModemStatus(hcom);
755
756 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
757 dcb.BaudRate = FASTBAUD;
758 dcb.ByteSize = 8;
759 dcb.Parity = NOPARITY;
760 dcb.fRtsControl=RTS_CONTROL_ENABLE;
761 dcb.fDtrControl=DTR_CONTROL_ENABLE;
762 dcb.StopBits = ONESTOPBIT;
763 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
764
765 ZeroMemory( &timeouts, sizeof(timeouts));
766 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
767 ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
768
769 before = GetTickCount();
770 SetLastError(0xdeadbeef);
771 res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
772 LastError = GetLastError();
773 after = GetTickCount();
774 ok( res == TRUE, "A timed-out read should return TRUE\n");
775 ok( LastError == 0xdeadbeef, "err=%d\n", LastError);
776 timediff = after - before;
777 ok( timediff > TIMEOUT>>2 && timediff < TIMEOUT *2,
778 "Unexpected TimeOut %d, expected %d\n", timediff, TIMEOUT);
779
780 CloseHandle(hcom);
781 }
782
783 static void test_waittxempty(void)
784 {
785 HANDLE hcom;
786 DCB dcb;
787 COMMTIMEOUTS timeouts;
788 char tbuf[]="test_waittxempty";
789 DWORD before, after, bytes, timediff, evtmask, errors, i;
790 BOOL res;
791 DWORD baud = SLOWBAUD;
792 OVERLAPPED ovl_write, ovl_wait, ovl_wait2;
793 COMSTAT stat;
794
795 hcom = test_OpenComm(TRUE);
796 if (hcom == INVALID_HANDLE_VALUE) return;
797
798 /* set a low baud rate to have ample time*/
799 res = GetCommState(hcom, &dcb);
800 ok(res, "GetCommState error %d\n", GetLastError());
801 dcb.BaudRate = baud;
802 dcb.ByteSize = 8;
803 dcb.Parity = NOPARITY;
804 dcb.fRtsControl=RTS_CONTROL_ENABLE;
805 dcb.fDtrControl=DTR_CONTROL_ENABLE;
806 dcb.StopBits = ONESTOPBIT;
807 res = SetCommState(hcom, &dcb);
808 ok(res, "SetCommState error %d\n", GetLastError());
809
810 ZeroMemory( &timeouts, sizeof(timeouts));
811 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
812 res = SetCommTimeouts(hcom, &timeouts);
813 ok(res,"SetCommTimeouts error %d\n", GetLastError());
814
815 res = SetupComm(hcom, 1024, 1024);
816 ok(res, "SetUpComm error %d\n", GetLastError());
817
818 /* calling SetCommMask after WriteFile leads to WaitCommEvent failures
819 * due to timeout (no events) under testbot VMs and VirtualBox
820 */
821 res = SetCommMask(hcom, EV_TXEMPTY);
822 ok(res, "SetCommMask error %d\n", GetLastError());
823
824 SetLastError(0xdeadbeef);
825 res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, NULL);
826 ok(!res, "WriteFile on an overlapped handle without ovl structure should fail\n");
827 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
828
829 S(U(ovl_write)).Offset = 0;
830 S(U(ovl_write)).OffsetHigh = 0;
831 ovl_write.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
832 before = GetTickCount();
833 SetLastError(0xdeadbeef);
834 res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, &ovl_write);
835 after = GetTickCount();
836 ok((!res && GetLastError() == ERROR_IO_PENDING) || (res && bytes == sizeof(tbuf)),
837 "WriteFile returned %d, written %u bytes, error %d\n", res, bytes, GetLastError());
838 if (!res) ok(!bytes, "expected 0, got %u\n", bytes);
839 ok(after - before < 30, "WriteFile took %d ms to write %d Bytes at %d Baud\n",
840 after - before, bytes, baud);
841 /* don't wait for WriteFile completion */
842
843 S(U(ovl_wait)).Offset = 0;
844 S(U(ovl_wait)).OffsetHigh = 0;
845 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
846 evtmask = 0;
847 before = GetTickCount();
848 SetLastError(0xdeadbeef);
849 res = WaitCommEvent(hcom, &evtmask, &ovl_wait);
850 ok(!res && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent error %d\n", GetLastError());
851 after = GetTickCount();
852 ok(after - before < 30, "WaitCommEvent should have returned immediately, took %d ms\n", after - before);
853 res = WaitForSingleObject(ovl_wait.hEvent, 1500);
854 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
855 if (res == WAIT_OBJECT_0)
856 {
857 res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
858 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
859 ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
860 res = TRUE;
861 }
862 else
863 {
864 /* unblock pending wait */
865 trace("recovering after WAIT_TIMEOUT...\n");
866 res = SetCommMask(hcom, EV_TXEMPTY);
867 ok(res, "SetCommMask error %d\n", GetLastError());
868
869 res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
870 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
871
872 res = FALSE;
873 }
874 after = GetTickCount();
875 ok(res, "WaitCommEvent error %d\n", GetLastError());
876 ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask);
877 CloseHandle(ovl_wait.hEvent);
878
879 timediff = after - before;
880 trace("WaitCommEvent for EV_TXEMPTY took %d ms (timeout 1500)\n", timediff);
881 ok(timediff < 1200, "WaitCommEvent used %d ms for waiting\n", timediff);
882
883 res = WaitForSingleObject(ovl_write.hEvent, 0);
884 ok(res == WAIT_OBJECT_0, "WriteFile failed with a timeout\n");
885 res = GetOverlappedResult(hcom, &ovl_write, &bytes, FALSE);
886 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
887 ok(bytes == sizeof(tbuf), "expected %u, written %u\n", (UINT)sizeof(tbuf), bytes);
888 CloseHandle(ovl_write.hEvent);
889
890 CloseHandle(hcom);
891
892 for (i = 0; i < 2; i++)
893 {
894 hcom = test_OpenComm(TRUE);
895 if (hcom == INVALID_HANDLE_VALUE) return;
896
897 res = SetCommMask(hcom, EV_TXEMPTY);
898 ok(res, "SetCommMask error %d\n", GetLastError());
899
900 if (i == 0)
901 {
902 S(U(ovl_write)).Offset = 0;
903 S(U(ovl_write)).OffsetHigh = 0;
904 ovl_write.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
905 before = GetTickCount();
906 SetLastError(0xdeadbeef);
907 res = WriteFile(hcom, tbuf, sizeof(tbuf), &bytes, &ovl_write);
908 ok((!res && GetLastError() == ERROR_IO_PENDING) || (res && bytes == sizeof(tbuf)),
909 "WriteFile returned %d, written %u bytes, error %d\n", res, bytes, GetLastError());
910 if (!res) ok(!bytes, "expected 0, got %u\n", bytes);
911
912 ClearCommError(hcom, &errors, &stat);
913 ok(stat.cbInQue == 0, "InQueue should be empty, got %d bytes\n", stat.cbInQue);
914 ok(stat.cbOutQue != 0 || broken(stat.cbOutQue == 0) /* VM */, "OutQueue should not be empty\n");
915 ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors);
916
917 res = GetOverlappedResult(hcom, &ovl_write, &bytes, TRUE);
918 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
919 ok(bytes == sizeof(tbuf), "expected %u, written %u\n", (UINT)sizeof(tbuf), bytes);
920 CloseHandle(ovl_write.hEvent);
921
922 res = FlushFileBuffers(hcom);
923 ok(res, "FlushFileBuffers error %d\n", GetLastError());
924 }
925
926 ClearCommError(hcom, &errors, &stat);
927 ok(stat.cbInQue == 0, "InQueue should be empty, got %d bytes\n", stat.cbInQue);
928 ok(stat.cbOutQue == 0, "OutQueue should be empty, got %d bytes\n", stat.cbOutQue);
929 ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors);
930
931 S(U(ovl_wait)).Offset = 0;
932 S(U(ovl_wait)).OffsetHigh = 0;
933 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
934 evtmask = 0;
935 SetLastError(0xdeadbeef);
936 res = WaitCommEvent(hcom, &evtmask, &ovl_wait);
937 ok(res /* busy system */ || GetLastError() == ERROR_IO_PENDING,
938 "%d: WaitCommEvent error %d\n", i, GetLastError());
939
940 res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
941 if (i == 0)
942 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
943 else
944 ok(res == WAIT_TIMEOUT, "WaitCommEvent should fail with a timeout\n");
945 if (res == WAIT_OBJECT_0)
946 {
947 res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
948 ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
949 ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
950 ok(res, "WaitCommEvent error %d\n", GetLastError());
951 ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask);
952 }
953 else
954 {
955 ok(!evtmask, "WaitCommEvent: expected 0, got %#x\n", evtmask);
956
957 S(U(ovl_wait2)).Offset = 0;
958 S(U(ovl_wait2)).OffsetHigh = 0;
959 ovl_wait2.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
960 SetLastError(0xdeadbeef);
961 res = WaitCommEvent(hcom, &evtmask, &ovl_wait2);
962 ok(!res, "WaitCommEvent should fail if there is a pending wait\n");
963 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
964 CloseHandle(ovl_wait2.hEvent);
965
966 /* unblock pending wait */
967 trace("recovering after WAIT_TIMEOUT...\n");
968 res = SetCommMask(hcom, EV_TXEMPTY);
969 ok(res, "SetCommMask error %d\n", GetLastError());
970
971 res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
972 ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
973 CloseHandle(ovl_wait.hEvent);
974 }
975
976 CloseHandle(hcom);
977 }
978 }
979
980 /* A new open handle should not return error or have bytes in the Queues */
981 static void test_ClearCommError(void)
982 {
983 HANDLE hcom;
984 DWORD errors;
985 COMSTAT lpStat;
986
987 hcom = test_OpenComm(FALSE);
988 if (hcom == INVALID_HANDLE_VALUE) return;
989
990 ok(ClearCommError(hcom, &errors, &lpStat), "ClearCommError failed\n");
991 ok(lpStat.cbInQue == 0, "Unexpected %d chars in InQueue\n", lpStat.cbInQue);
992 ok(lpStat.cbOutQue == 0, "Unexpected %d chars in OutQueue\n", lpStat.cbOutQue);
993 ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08x\n", errors);
994
995 CloseHandle(hcom);
996 }
997
998 static void test_non_pending_errors(void)
999 {
1000 HANDLE hcom;
1001 DCB dcb;
1002 DWORD err;
1003
1004 hcom = test_OpenComm(FALSE);
1005 if (hcom == INVALID_HANDLE_VALUE) return;
1006
1007 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1008 dcb.ByteSize = 255; /* likely bogus */
1009 ok(!SetCommState(hcom, &dcb), "SetCommState should have failed\n");
1010 ok(ClearCommError(hcom, &err, NULL), "ClearCommError should succeed\n");
1011 ok(!(err & CE_MODE), "ClearCommError shouldn't set CE_MODE byte in this case (%x)\n", err);
1012
1013 CloseHandle(hcom);
1014 }
1015
1016 static void test_LoopbackRead(void)
1017 {
1018 HANDLE hcom;
1019 DCB dcb;
1020 COMMTIMEOUTS timeouts;
1021 char rbuf[32];
1022 DWORD before, after, diff, read, read1, written, evtmask=0, i;
1023 BOOL res;
1024 char tbuf[]="test_LoopbackRead";
1025
1026 if (!loopback_txd_rxd) return;
1027
1028 hcom = test_OpenComm(FALSE);
1029 if (hcom == INVALID_HANDLE_VALUE) return;
1030
1031 trace("Starting test_LoopbackRead\n");
1032 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1033 dcb.BaudRate = FASTBAUD;
1034 dcb.ByteSize = 8;
1035 dcb.Parity = NOPARITY;
1036 dcb.fRtsControl=RTS_CONTROL_ENABLE;
1037 dcb.fDtrControl=DTR_CONTROL_ENABLE;
1038 dcb.StopBits = ONESTOPBIT;
1039 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1040
1041 ZeroMemory( &timeouts, sizeof(timeouts));
1042 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
1043 ok(SetCommTimeouts(hcom, &timeouts),"SetCommTimeouts failed\n");
1044
1045 ok(SetCommMask(hcom, EV_TXEMPTY), "SetCommMask failed\n");
1046
1047 before = GetTickCount();
1048 ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
1049 after = GetTickCount();
1050 ok(written == sizeof(tbuf),"WriteFile %d bytes written\n", written);
1051 diff = after -before;
1052
1053 /* make sure all bytes are written, so Readfile will succeed in one call*/
1054 ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
1055 before = GetTickCount();
1056 ok(evtmask == EV_TXEMPTY,
1057 "WaitCommEvent: Unexpected EvtMask 0x%08x, expected 0x%08x\n",
1058 evtmask, EV_TXEMPTY);
1059 trace("Write %d ms WaitCommEvent EV_TXEMPTY %d ms\n", diff, before- after);
1060
1061 read=0;
1062 ok(ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL), "Readfile failed\n");
1063 ok(read == sizeof(tbuf),"ReadFile read %d bytes, expected \"%s\"\n", read,rbuf);
1064
1065 /* Now do the same with a slower Baud rate.
1066 As we request more characters than written, we will hit the timeout
1067 */
1068
1069 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1070 dcb.BaudRate = 9600;
1071 dcb.ByteSize = 8;
1072 dcb.Parity = NOPARITY;
1073 dcb.fRtsControl=RTS_CONTROL_ENABLE;
1074 dcb.fDtrControl=DTR_CONTROL_ENABLE;
1075 dcb.StopBits = ONESTOPBIT;
1076 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1077
1078 ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n");
1079 ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
1080 ok(written == sizeof(tbuf),"WriteFile %d bytes written\n", written);
1081
1082 trace("WaitCommEventEV_RXCHAR\n");
1083 ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
1084 ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08x, expected 0x%08x\n",
1085 evtmask, EV_RXCHAR);
1086
1087 before = GetTickCount();
1088 res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
1089 after = GetTickCount();
1090 ok(res, "Readfile failed\n");
1091 ok(read == sizeof(tbuf),"ReadFile read %d bytes\n", read);
1092 diff = after - before;
1093 trace("Readfile for %d chars took %d ms\n", read, diff);
1094 ok( (diff > TIMEOUT - TIMEDELTA) && (diff < TIMEOUT + TIMEDELTA),
1095 "Timedout Wait took %d ms, expected around %d\n", diff, TIMEOUT);
1096
1097 /* now do a plain read with slow speed
1098 * This will result in several low level reads and a timeout to happen
1099 */
1100 dcb.BaudRate = SLOWBAUD;
1101 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1102 ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
1103 before = GetTickCount();
1104 read = 0;
1105 read1 =0;
1106 i=0;
1107 do
1108 {
1109 res = ReadFile(hcom, rbuf+read, sizeof(rbuf)-read, &read1, NULL);
1110 ok(res, "Readfile failed\n");
1111 read += read1;
1112 i++;
1113 }
1114 while ((read < sizeof(tbuf)) && (i <10));
1115 after = GetTickCount();
1116 ok( read == sizeof(tbuf),"ReadFile read %d bytes\n", read);
1117 trace("Plain Read for %d char at %d baud took %d ms\n", read, SLOWBAUD, after-before);
1118
1119 CloseHandle(hcom);
1120 }
1121
1122 static void test_LoopbackCtsRts(void)
1123 {
1124 HANDLE hcom;
1125 DWORD ModemStat = 0, defaultStat = 0;
1126 DCB dcb;
1127
1128 if (!loopback_rts_cts) return;
1129
1130 hcom = test_OpenComm(FALSE);
1131 if (hcom == INVALID_HANDLE_VALUE) return;
1132
1133 memset (&dcb, 0, sizeof (dcb));
1134 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1135 if (dcb.fRtsControl == RTS_CONTROL_HANDSHAKE)
1136 {
1137 trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate RTS\n");
1138 CloseHandle(hcom);
1139 return;
1140 }
1141 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1142 /* XP returns some values in the low nibble, so mask them out*/
1143 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1144 if(defaultStat & MS_CTS_ON)
1145 {
1146 ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
1147 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1148 ok ((ModemStat & MS_CTS_ON) == 0, "CTS didn't react: 0x%04x, expected 0x%04x\n",
1149 ModemStat, (defaultStat & ~MS_CTS_ON));
1150 ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to clear RTS\n");
1151 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1152 ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04x, expected 0x%04x\n",
1153 ModemStat, defaultStat);
1154 }
1155 else
1156 {
1157 ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to set RTS\n");
1158 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1159 ok ((ModemStat & MS_CTS_ON) == MS_CTS_ON,
1160 "CTS didn't react: 0x%04x, expected 0x%04x\n",
1161 ModemStat, (defaultStat | MS_CTS_ON));
1162 ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
1163 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1164 ok (ModemStat == defaultStat, "Failed to restore CTS: 0x%04x, expected 0x%04x\n",
1165 ModemStat, defaultStat);
1166 }
1167
1168 CloseHandle(hcom);
1169 }
1170
1171 static void test_LoopbackDtrDcd(void)
1172 {
1173 HANDLE hcom;
1174 DWORD ModemStat = 0, defaultStat = 0;
1175 DCB dcb;
1176
1177 if (!loopback_dtr_dcd) return;
1178
1179 hcom = test_OpenComm(FALSE);
1180 if (hcom == INVALID_HANDLE_VALUE) return;
1181
1182 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1183 if (dcb.fDtrControl == DTR_CONTROL_HANDSHAKE)
1184 {
1185 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1186 CloseHandle(hcom);
1187 return;
1188 }
1189 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1190 /* XP returns some values in the low nibble, so mask them out*/
1191 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1192 if(defaultStat & MS_RLSD_ON)
1193 {
1194 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1195 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1196 ok ((ModemStat & MS_RLSD_ON) == 0, "RLSD didn't react: 0x%04x, expected 0x%04x\n",
1197 ModemStat, (defaultStat & ~MS_RLSD_ON));
1198 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1199 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1200 ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04x, expected 0x%04x\n",
1201 ModemStat, defaultStat);
1202 }
1203 else
1204 {
1205 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1206 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1207 ok ((ModemStat & MS_RLSD_ON) == MS_RLSD_ON,
1208 "RLSD didn't react: 0x%04x, expected 0x%04x\n",
1209 ModemStat, (defaultStat | MS_RLSD_ON));
1210 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1211 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1212 ok (ModemStat == defaultStat, "Failed to restore RLSD: 0x%04x, expected 0x%04x\n",
1213 ModemStat, defaultStat);
1214 }
1215
1216 CloseHandle(hcom);
1217 }
1218
1219 static void test_LoopbackDtrDsr(void)
1220 {
1221 HANDLE hcom;
1222 DWORD ModemStat = 0, defaultStat = 0;
1223 DCB dcb;
1224
1225 if (!loopback_dtr_dsr) return;
1226
1227 hcom = test_OpenComm(FALSE);
1228 if (hcom == INVALID_HANDLE_VALUE) return;
1229
1230 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1231 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1232 {
1233 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1234 CloseHandle(hcom);
1235 return;
1236 }
1237 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1238 /* XP returns some values in the low nibble, so mask them out*/
1239 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1240 if(defaultStat & MS_DSR_ON)
1241 {
1242 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1243 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1244 ok ((ModemStat & MS_DSR_ON) == 0, "CTS didn't react: 0x%04x, expected 0x%04x\n",
1245 ModemStat, (defaultStat & ~MS_DSR_ON));
1246 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to clear DTR\n");
1247 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1248 ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04x, expected 0x%04x\n",
1249 ModemStat, defaultStat);
1250 }
1251 else
1252 {
1253 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1254 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1255 ok ((ModemStat & MS_DSR_ON) == MS_DSR_ON,
1256 "CTS didn't react: 0x%04x,expected 0x%04x\n",
1257 ModemStat, (defaultStat | MS_DSR_ON));
1258 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1259 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1260 ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04x, expected 0x%04x\n",
1261 ModemStat, defaultStat);
1262 }
1263
1264 CloseHandle(hcom);
1265 }
1266
1267 static void test_LoopbackDtrRing(void)
1268 {
1269 HANDLE hcom;
1270 DWORD ModemStat = 0, defaultStat = 0;
1271 DCB dcb;
1272
1273 if (!loopback_dtr_ring) return;
1274
1275 hcom = test_OpenComm(FALSE);
1276 if (hcom == INVALID_HANDLE_VALUE) return;
1277
1278 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1279 if (dcb.fDtrControl == DTR_CONTROL_HANDSHAKE)
1280 {
1281 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1282 CloseHandle(hcom);
1283 return;
1284 }
1285 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1286 /* XP returns some values in the low nibble, so mask them out*/
1287 defaultStat &= MS_CTS_ON|MS_DSR_ON|MS_RING_ON|MS_RLSD_ON;
1288 if(defaultStat & MS_RING_ON)
1289 {
1290 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1291 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1292 ok ((ModemStat & MS_RING_ON) == 0, "RING didn't react: 0x%04x, expected 0x%04x\n",
1293 ModemStat, (defaultStat & ~MS_RING_ON));
1294 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1295 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1296 ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04x, expected 0x%04x\n",
1297 ModemStat, defaultStat);
1298 }
1299 else
1300 {
1301 ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
1302 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1303 ok ((ModemStat & MS_RING_ON) == MS_RING_ON,
1304 "RING didn't react: 0x%04x,expected 0x%04x\n",
1305 ModemStat, (defaultStat | MS_RING_ON));
1306 ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
1307 ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
1308 ok (ModemStat == defaultStat, "Failed to restore RING: 0x%04x, expected 0x%04x\n",
1309 ModemStat, defaultStat);
1310 }
1311
1312 CloseHandle(hcom);
1313 }
1314
1315 /*
1316 * Set up a WaitCommEvent for anything in the receive buffer,
1317 * then write to TX to put a character
1318 * into the RX buffer
1319 * Need Loopback TX->RX
1320 */
1321
1322 static void test_WaitRx(void)
1323 {
1324 OVERLAPPED overlapped, overlapped_w;
1325 HANDLE hcom, hComPortEvent, hComWriteEvent;
1326 DWORD before, after, after1, diff, success_wait = FALSE, success_write;
1327 DWORD err_wait, err_write, written, evtmask=0;
1328
1329 if (!loopback_txd_rxd) return;
1330
1331 hcom = test_OpenComm(TRUE);
1332 if (hcom == INVALID_HANDLE_VALUE) return;
1333
1334 ok(SetCommMask(hcom, EV_RXCHAR), "SetCommMask failed\n");
1335 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1336 ok(hComPortEvent != 0, "CreateEvent failed\n");
1337 ZeroMemory( &overlapped, sizeof(overlapped));
1338 overlapped.hEvent = hComPortEvent;
1339
1340 hComWriteEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1341 ok(hComWriteEvent != NULL, "CreateEvent res %d\n", GetLastError());
1342 ZeroMemory( &overlapped_w, sizeof(overlapped_w));
1343 overlapped_w.hEvent = hComWriteEvent;
1344
1345 before = GetTickCount();
1346 success_wait = WaitCommEvent(hcom, &evtmask, &overlapped);
1347 err_wait = GetLastError();
1348 after = GetTickCount();
1349 trace("Success 0x%08x err %d evtmask 0x%08x\n", success_wait, err_wait, evtmask);
1350 ok(success_wait || err_wait == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1351 trace("overlapped WaitCommEvent returned.\n");
1352
1353 success_write= WriteFile(hcom, "X", 1, &written, &overlapped_w);
1354 err_write = GetLastError();
1355 ok(success_write || err_write == ERROR_IO_PENDING,
1356 "overlapped WriteFile failed, err %d\n",
1357 err_write);
1358
1359 if (!success_write && (err_write == ERROR_IO_PENDING)) {
1360 success_write = WaitForSingleObjectEx(hComWriteEvent, TIMEOUT, TRUE);
1361 err_write = GetLastError();
1362 ok(success_write == WAIT_OBJECT_0, "WaitForSingleObjectEx, res %d, err %d\n",
1363 success_write, err_write);
1364 }
1365 Sleep(TIMEOUT >>1);
1366 success_write = GetOverlappedResult(hcom, &overlapped_w, &written, FALSE);
1367 err_write = GetLastError();
1368
1369 trace("Write after Wait res 0x%08x err %d\n",success_write, err_write);
1370 ok(success_write && written ==1, "Write after Wait res 0x%08x err %d\n",
1371 success_write, err_write);
1372
1373 if (!success_wait && (err_wait == ERROR_IO_PENDING)) {
1374 success_wait = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
1375 err_wait = GetLastError();
1376 ok(success_wait == WAIT_OBJECT_0, "wait hComPortEvent, res 0x%08x, err %d\n",
1377 success_wait, err_wait);
1378 }
1379 success_wait = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1380 err_wait = GetLastError();
1381 after1 = GetTickCount();
1382 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1383 success_wait, err_wait, evtmask, after-before, after1-before);
1384
1385 ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08x, expected 0x%08x\n",
1386 evtmask, EV_RXCHAR);
1387 diff = after1 - before;
1388 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1389 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1390
1391 CloseHandle(hcom);
1392 }
1393
1394 /* Change the controlling line after the given timeout to the given state
1395 By the loopback, this should trigger the WaitCommEvent
1396 */
1397 static DWORD CALLBACK toggle_ctlLine(LPVOID arg)
1398 {
1399 DWORD_PTR *args = arg;
1400 DWORD timeout = args[0];
1401 DWORD ctl = args[1];
1402 HANDLE hcom = (HANDLE) args[2];
1403 HANDLE hComPortEvent = (HANDLE) args[3];
1404 DWORD success, err;
1405
1406 trace("toggle_ctlLine timeout %d ctl 0x%08x handle %p\n", timeout, ctl, hcom );
1407 Sleep(timeout);
1408 ok(EscapeCommFunction(hcom, ctl),"EscapeCommFunction 0x%08x failed\n", ctl);
1409 trace("toggle_ctline done\n");
1410 success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
1411 err = GetLastError();
1412 trace("toggle_ctline WaitForSingleObjectEx res 0x%08x err %d\n",
1413 success, err);
1414 return 0;
1415 }
1416
1417 /*
1418 * Wait for a change in CTS
1419 * Needs Loopback from DTR to CTS
1420 */
1421 static void test_WaitCts(void)
1422 {
1423 DCB dcb;
1424 OVERLAPPED overlapped;
1425 HANDLE hcom, hComPortEvent, alarmThread;
1426 DWORD_PTR args[4];
1427 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0;
1428
1429 if (!loopback_rts_cts) return;
1430
1431 hcom = test_OpenComm(TRUE);
1432 if (hcom == INVALID_HANDLE_VALUE) return;
1433
1434 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1435 dcb.fRtsControl=RTS_CONTROL_ENABLE;
1436 dcb.fDtrControl=DTR_CONTROL_ENABLE;
1437 ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
1438 if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
1439 {
1440 trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1441 CloseHandle(hcom);
1442 return;
1443 }
1444 args[0]= TIMEOUT >>1;
1445 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1446 if(defaultStat & MS_CTS_ON)
1447 args[1] = CLRRTS;
1448 else
1449 args[1] = SETRTS;
1450 args[2]=(DWORD_PTR)hcom;
1451
1452 trace("test_WaitCts timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1453
1454 ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n");
1455 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1456 ok(hComPortEvent != 0, "CreateEvent failed\n");
1457 args[3] = (DWORD_PTR)hComPortEvent;
1458 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1459 /* Wait a minimum to let the thread start up */
1460 Sleep(10);
1461 trace("Thread created\n");
1462 ok(alarmThread !=0 , "CreateThread Failed\n");
1463
1464 ZeroMemory( &overlapped, sizeof(overlapped));
1465 overlapped.hEvent = hComPortEvent;
1466 before = GetTickCount();
1467 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1468 err = GetLastError();
1469 after = GetTickCount();
1470
1471 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1472 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1473 trace("overlapped WaitCommEvent returned.\n");
1474 if (!success && (err == ERROR_IO_PENDING))
1475 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1476 "WaitCts hComPortEvent failed\n");
1477 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1478 err = GetLastError();
1479 after1 = GetTickCount();
1480 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1481 success, err, evtmask, after-before, after1-before);
1482
1483 ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08x, expected 0x%08x\n",
1484 evtmask, EV_CTS);
1485 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1486 if(defaultStat & MS_CTS_ON)
1487 ok((evtmask & MS_CTS_ON) == 0,"CTS didn't change state!\n");
1488 else
1489 ok((evtmask & MS_CTS_ON), "CTS didn't change state!\n");
1490
1491 diff = after1 - before;
1492 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1493 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1494
1495 /*restore RTS Settings*/
1496 if(defaultStat & MS_CTS_ON)
1497 args[1] = SETRTS;
1498 else
1499 args[1] = CLRRTS;
1500
1501 CloseHandle(hcom);
1502 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1503 CloseHandle( alarmThread );
1504 }
1505
1506 /* Change the Comm Mask while a Wait is going on
1507 WaitCommevent should return with a EVTMASK set to zero
1508 */
1509 static DWORD CALLBACK reset_CommMask(LPVOID arg)
1510 {
1511 DWORD_PTR *args = arg;
1512 DWORD timeout = args[0];
1513 HANDLE hcom = (HANDLE) args[1];
1514
1515 trace(" Changing CommMask on the fly for handle %p after timeout %d\n",
1516 hcom, timeout);
1517 Sleep(timeout);
1518 ok(SetCommMask(hcom, 0),"SetCommMask %p failed\n", hcom);
1519 trace("SetCommMask changed\n");
1520 return 0;
1521 }
1522
1523 /* Set up a Wait for a change on CTS. We don't toggle any line, but we
1524 reset the CommMask and expect the wait to return with a mask of 0
1525 No special port connections needed
1526 */
1527 static void test_AbortWaitCts(void)
1528 {
1529 DCB dcb;
1530 OVERLAPPED overlapped;
1531 HANDLE hcom, hComPortEvent, alarmThread;
1532 DWORD_PTR args[2];
1533 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
1534
1535 hcom = test_OpenComm(TRUE);
1536 if (hcom == INVALID_HANDLE_VALUE) return;
1537
1538 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1539 if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
1540 {
1541 trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1542 CloseHandle(hcom);
1543 return;
1544 }
1545 args[0]= TIMEOUT >>1;
1546 args[1]= (DWORD_PTR)hcom;
1547
1548 trace("test_AbortWaitCts timeout %ld handle %p\n",args[0], hcom);
1549
1550 ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n");
1551 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1552 ok(hComPortEvent != 0, "CreateEvent failed\n");
1553 alarmThread = CreateThread(NULL, 0, reset_CommMask, args, 0, &alarmThreadId);
1554 /* Wait a minimum to let the thread start up */
1555 Sleep(10);
1556 trace("Thread created\n");
1557 ok(alarmThread !=0 , "CreateThread Failed\n");
1558
1559 ZeroMemory( &overlapped, sizeof(overlapped));
1560 overlapped.hEvent = hComPortEvent;
1561 before = GetTickCount();
1562 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1563 err = GetLastError();
1564 after = GetTickCount();
1565
1566 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1567 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1568 trace("overlapped WaitCommEvent returned.\n");
1569 if (!success && (err == ERROR_IO_PENDING))
1570 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1571 "AbortWaitCts hComPortEvent failed\n");
1572 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1573 err = GetLastError();
1574 after1 = GetTickCount();
1575 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1576 success, err, evtmask, after-before, after1-before);
1577
1578 ok(evtmask == 0, "Incorrect EventMask 0x%08x returned on Wait aborted bu SetCommMask, expected 0x%08x\n",
1579 evtmask, 0);
1580 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1581 diff = after1 - before;
1582 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1583 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1584
1585 CloseHandle(hcom);
1586 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1587 CloseHandle( alarmThread );
1588 }
1589
1590 /*
1591 * Wait for a change in DSR
1592 * Needs Loopback from DTR to DSR
1593 */
1594 static void test_WaitDsr(void)
1595 {
1596 DCB dcb;
1597 OVERLAPPED overlapped;
1598 HANDLE hcom, hComPortEvent, alarmThread;
1599 DWORD_PTR args[3];
1600 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0;
1601
1602 if (!loopback_dtr_dsr) return;
1603
1604 hcom = test_OpenComm(TRUE);
1605 if (hcom == INVALID_HANDLE_VALUE) return;
1606
1607 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1608 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1609 {
1610 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1611 CloseHandle(hcom);
1612 return;
1613 }
1614 args[0]= TIMEOUT >>1;
1615 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1616 if(defaultStat & MS_DSR_ON)
1617 args[1] = CLRDTR;
1618 else
1619 args[1] = SETDTR;
1620 args[2]= (DWORD_PTR)hcom;
1621
1622 trace("test_WaitDsr timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1623
1624 ok(SetCommMask(hcom, EV_DSR), "SetCommMask failed\n");
1625 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1626 ok(hComPortEvent != 0, "CreateEvent failed\n");
1627 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1628 ok(alarmThread !=0 , "CreateThread Failed\n");
1629
1630 ZeroMemory( &overlapped, sizeof(overlapped));
1631 overlapped.hEvent = hComPortEvent;
1632 before = GetTickCount();
1633 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1634 err = GetLastError();
1635 after = GetTickCount();
1636
1637 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1638 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1639 trace("overlapped WaitCommEvent returned.\n");
1640 if (!success && (err == ERROR_IO_PENDING))
1641 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1642 "wait hComPortEvent failed\n");
1643 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1644 err = GetLastError();
1645 after1 = GetTickCount();
1646 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1647 success, err, evtmask, after-before, after1-before);
1648
1649 ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08x, expected 0x%08x\n",
1650 evtmask, EV_DSR);
1651 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1652 if(defaultStat & MS_DSR_ON)
1653 ok((evtmask & MS_DSR_ON) == 0,"DTR didn't change state!\n");
1654 else
1655 ok((evtmask & MS_DSR_ON), "DTR didn't change state!\n");
1656
1657 diff = after1 - before;
1658 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1659 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1660
1661 /*restore RTS Settings*/
1662 if(defaultStat & MS_DSR_ON)
1663 args[1] = SETDTR;
1664 else
1665 args[1] = CLRDTR;
1666
1667 CloseHandle(hcom);
1668 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1669 CloseHandle( alarmThread );
1670 }
1671
1672 /*
1673 * Wait for a Ring
1674 * Needs Loopback from DTR to RING
1675 */
1676 static void test_WaitRing(void)
1677 {
1678 DCB dcb;
1679 OVERLAPPED overlapped;
1680 HANDLE hcom, hComPortEvent, alarmThread;
1681 DWORD_PTR args[3];
1682 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat;
1683 BOOL ret;
1684
1685 if (!loopback_dtr_ring) return;
1686
1687 hcom = test_OpenComm(TRUE);
1688 if (hcom == INVALID_HANDLE_VALUE) return;
1689
1690 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1691 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1692 {
1693 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1694 CloseHandle(hcom);
1695 return;
1696 }
1697 args[0]= TIMEOUT >>1;
1698 ok((ret = GetCommModemStatus(hcom, &defaultStat)), "GetCommModemStatus failed\n");
1699 if (!ret) {
1700 skip("modem status failed -> skip.\n");
1701 CloseHandle(hcom);
1702 return;
1703 }
1704 if(defaultStat & MS_RING_ON)
1705 args[1] = CLRDTR;
1706 else
1707 args[1] = SETDTR;
1708 args[2]=(DWORD_PTR) hcom;
1709
1710 trace("test_WaitRing timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1711
1712 ok(SetCommMask(hcom, EV_RING), "SetCommMask failed\n");
1713 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1714 ok(hComPortEvent != 0, "CreateEvent failed\n");
1715 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1716 ok(alarmThread !=0 , "CreateThread Failed\n");
1717
1718 ZeroMemory( &overlapped, sizeof(overlapped));
1719 overlapped.hEvent = hComPortEvent;
1720 before = GetTickCount();
1721 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1722 err = GetLastError();
1723 after = GetTickCount();
1724
1725 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1726 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1727 trace("overlapped WaitCommEvent returned.\n");
1728 if (!success && (err == ERROR_IO_PENDING))
1729 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1730 "wait hComPortEvent failed\n");
1731 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1732 err = GetLastError();
1733 after1 = GetTickCount();
1734 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1735 success, err, evtmask, after-before, after1-before);
1736
1737 ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08x, expected 0x%08x\n",
1738 evtmask, EV_RING);
1739 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1740 if(defaultStat & MS_RING_ON)
1741 ok((evtmask & MS_RING_ON) == 0,"DTR didn't change state!\n");
1742 else
1743 ok((evtmask & MS_RING_ON), "DTR didn't change state!\n");
1744
1745 diff = after1 - before;
1746 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1747 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1748
1749 /*restore RTS Settings*/
1750 if(defaultStat & MS_RING_ON)
1751 args[1] = SETDTR;
1752 else
1753 args[1] = CLRDTR;
1754
1755 CloseHandle(hcom);
1756 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1757 CloseHandle( alarmThread );
1758 }
1759 /*
1760 * Wait for a change in DCD
1761 * Needs Loopback from DTR to DCD
1762 */
1763 static void test_WaitDcd(void)
1764 {
1765 DCB dcb;
1766 OVERLAPPED overlapped;
1767 HANDLE hcom, hComPortEvent, alarmThread;
1768 DWORD_PTR args[3];
1769 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0, defaultStat = 0;
1770
1771 if (!loopback_dtr_dcd) return;
1772
1773 hcom = test_OpenComm(TRUE);
1774 if (hcom == INVALID_HANDLE_VALUE) return;
1775
1776 ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
1777 if (dcb.fDtrControl == DTR_CONTROL_DISABLE)
1778 {
1779 trace("DTR_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
1780 CloseHandle(hcom);
1781 return;
1782 }
1783 args[0]= TIMEOUT >>1;
1784 ok(GetCommModemStatus(hcom, &defaultStat), "GetCommModemStatus failed\n");
1785 if(defaultStat & MS_RLSD_ON)
1786 args[1] = CLRDTR;
1787 else
1788 args[1] = SETDTR;
1789 args[2]= (DWORD_PTR)hcom;
1790
1791 trace("test_WaitDcd timeout %ld clt 0x%08lx handle %p\n",args[0], args[1], hcom);
1792
1793 ok(SetCommMask(hcom, EV_RLSD), "SetCommMask failed\n");
1794 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1795 ok(hComPortEvent != 0, "CreateEvent failed\n");
1796 alarmThread = CreateThread(NULL, 0, toggle_ctlLine, args, 0, &alarmThreadId);
1797 ok(alarmThread !=0 , "CreateThread Failed\n");
1798
1799 ZeroMemory( &overlapped, sizeof(overlapped));
1800 overlapped.hEvent = hComPortEvent;
1801 before = GetTickCount();
1802 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1803 err = GetLastError();
1804 after = GetTickCount();
1805
1806 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1807 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1808 trace("overlapped WaitCommEvent returned.\n");
1809 if (!success && (err == ERROR_IO_PENDING))
1810 ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
1811 "wait hComPortEvent failed\n");
1812 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1813 err = GetLastError();
1814 after1 = GetTickCount();
1815 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1816 success, err, evtmask, after-before, after1-before);
1817
1818 ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08x, expected 0x%08x\n",
1819 evtmask, EV_RLSD);
1820 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1821 if(defaultStat & MS_RLSD_ON)
1822 ok((evtmask & MS_RLSD_ON) == 0,"DTR didn't change state!\n");
1823 else
1824 ok((evtmask & MS_RLSD_ON), "DTR didn't change state!\n");
1825
1826 diff = after1 - before;
1827 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1828 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1829
1830 /*restore RTS Settings*/
1831 if(defaultStat & MS_RLSD_ON)
1832 args[1] = SETDTR;
1833 else
1834 args[1] = CLRDTR;
1835
1836 CloseHandle(hcom);
1837 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1838 CloseHandle( alarmThread );
1839 }
1840
1841 /*
1842 Set Break after timeout
1843 */
1844 static DWORD CALLBACK set_CommBreak(LPVOID arg)
1845 {
1846 DWORD_PTR *args = arg;
1847 DWORD timeout = args[0];
1848 HANDLE hcom = (HANDLE) args[1];
1849
1850 trace("SetCommBreak for handle %p after timeout %d\n",
1851 hcom, timeout);
1852 Sleep(timeout);
1853 ok(SetCommBreak(hcom),"SetCommBreak %p failed\n", hcom);
1854 trace("SetCommBreak done\n");
1855 return 0;
1856 }
1857
1858 /*
1859 Wait for the Break condition (TX resp. RX active)
1860 Needs Loopback TX-RX
1861 */
1862 static void test_WaitBreak(void)
1863 {
1864 OVERLAPPED overlapped;
1865 HANDLE hcom, hComPortEvent, alarmThread;
1866 DWORD_PTR args[2];
1867 DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
1868
1869 if (!loopback_txd_rxd) return;
1870
1871 hcom = test_OpenComm(TRUE);
1872 if (hcom == INVALID_HANDLE_VALUE) return;
1873
1874 ok(SetCommMask(hcom, EV_BREAK), "SetCommMask failed\n");
1875 hComPortEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
1876 ok(hComPortEvent != 0, "CreateEvent failed\n");
1877
1878 trace("test_WaitBreak\n");
1879 args[0]= TIMEOUT >>1;
1880 args[1]= (DWORD_PTR)hcom;
1881 alarmThread = CreateThread(NULL, 0, set_CommBreak, args, 0, &alarmThreadId);
1882 /* Wait a minimum to let the thread start up */
1883 Sleep(10);
1884 trace("Thread created\n");
1885 ok(alarmThread !=0 , "CreateThread Failed\n");
1886
1887 ZeroMemory( &overlapped, sizeof(overlapped));
1888 overlapped.hEvent = hComPortEvent;
1889 before = GetTickCount();
1890 success = WaitCommEvent(hcom, &evtmask, &overlapped);
1891 err = GetLastError();
1892 after = GetTickCount();
1893
1894 trace("Success 0x%08x err %d evtmask 0x%08x\n", success, err, evtmask);
1895 ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
1896 trace("overlapped WaitCommEvent returned.\n");
1897
1898 if (!success && (err == ERROR_IO_PENDING))
1899 {
1900 success = WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE);
1901 ok(!success, "wait hComPortEvent res %d\n", GetLastError());
1902 }
1903 success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
1904 err = GetLastError();
1905 after1 = GetTickCount();
1906 trace("Success 0x%08x err %d evtmask 0x%08x diff1 %d, diff2 %d\n",
1907 success, err, evtmask, after-before, after1-before);
1908
1909 ok(evtmask & EV_BREAK, "Failed to detect EV_BREAK: 0x%08x, expected 0x%08x\n",
1910 evtmask, EV_BREAK);
1911 ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
1912
1913 diff = after1 - before;
1914 ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
1915 "Unexpected time %d, expected around %d\n", diff, TIMEOUT>>1);
1916
1917 ok(ClearCommBreak(hcom), "ClearCommBreak failed\n");
1918
1919 CloseHandle(hcom);
1920 ok( !WaitForSingleObject( alarmThread, 10000 ), "thread still running\n" );
1921 CloseHandle( alarmThread );
1922 }
1923
1924 static void test_stdio(void)
1925 {
1926 DCB dcb;
1927
1928 /* cygwin tries this to determine the stdin handle type */
1929 ok( !GetCommState( GetStdHandle(STD_INPUT_HANDLE), &dcb ), "GetCommState succeeded on stdin\n" );
1930 ok( GetLastError() == ERROR_INVALID_HANDLE || GetLastError() == ERROR_INVALID_FUNCTION,
1931 "got error %u\n", GetLastError() );
1932 }
1933
1934 static void test_WaitCommEvent(void)
1935 {
1936 HANDLE hcom;
1937 DWORD evtmask, ret, bytes, before, after, last_event_time;
1938 OVERLAPPED ovl_wait;
1939
1940 hcom = test_OpenComm(TRUE);
1941 if (hcom == INVALID_HANDLE_VALUE) return;
1942
1943 test_GetModemStatus(hcom);
1944
1945 ret = SetCommMask(hcom, 0x1fff);
1946 ok(ret, "SetCommMask error %d\n", GetLastError());
1947
1948 S(U(ovl_wait)).Offset = 0;
1949 S(U(ovl_wait)).OffsetHigh = 0;
1950 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
1951
1952 trace("waiting 10 secs for com port events (turn on/off the device)...\n");
1953 last_event_time = 0;
1954 before = GetTickCount();
1955 do
1956 {
1957 evtmask = 0;
1958 SetLastError(0xdeadbeef);
1959 ret = WaitCommEvent(hcom, &evtmask, &ovl_wait);
1960 ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError());
1961 if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */
1962 for (;;)
1963 {
1964 ret = WaitForSingleObject(ovl_wait.hEvent, 500);
1965 after = GetTickCount();
1966 if (ret == WAIT_OBJECT_0)
1967 {
1968 last_event_time = after;
1969 ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
1970 ok(ret, "GetOverlappedResult reported error %d\n", GetLastError());
1971 ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
1972 trace("WaitCommEvent: got events %#x\n", evtmask);
1973 test_GetModemStatus(hcom);
1974 break;
1975 }
1976 else
1977 {
1978 if (last_event_time || after - before >= 10000) goto done;
1979 }
1980 }
1981 } while (after - before < 10000);
1982
1983 done:
1984 CloseHandle(ovl_wait.hEvent);
1985 CloseHandle(hcom);
1986 }
1987
1988 static void test_FlushFileBuffers(void)
1989 {
1990 HANDLE hcom;
1991 DWORD ret, bytes, errors;
1992 COMSTAT stat;
1993
1994 hcom = test_OpenComm(FALSE);
1995 if (hcom == INVALID_HANDLE_VALUE) return;
1996
1997 ret = WriteFile(hcom, "\0\0\0\0\0\0\0", 7, &bytes, NULL);
1998 ok(ret, "WriteFile error %d\n", GetLastError());
1999 ok(bytes == 7, "expected 7, got %u\n", bytes);
2000
2001 ret = FlushFileBuffers(hcom);
2002 ok(ret, "FlushFileBuffers error %d\n", GetLastError());
2003
2004 ret = ClearCommError(hcom, &errors, &stat);
2005 ok(ret, "ClearCommError error %d\n", GetLastError());
2006 ok(stat.cbInQue == 0, "expected 0, got %d bytes in InQueue\n", stat.cbInQue);
2007 ok(stat.cbOutQue == 0, "expected 0, got %d bytes in OutQueue\n", stat.cbOutQue);
2008 ok(errors == 0, "expected errors 0, got %#x\n", errors);
2009
2010 CloseHandle(hcom);
2011 }
2012
2013 static void test_read_write(void)
2014 {
2015 static const char atz[]="ATZ\r\n";
2016 char buf[256];
2017 HANDLE hcom;
2018 DCB dcb;
2019 COMMTIMEOUTS timeouts;
2020 DWORD ret, bytes, status, evtmask, before, after, last_event_time;
2021 OVERLAPPED ovl_wait;
2022 IO_STATUS_BLOCK iob;
2023 LARGE_INTEGER offset;
2024 LONG i;
2025
2026 if (!pNtReadFile || !pNtWriteFile)
2027 {
2028 win_skip("not running on NT, skipping test\n");
2029 return;
2030 }
2031
2032 hcom = test_OpenComm(TRUE);
2033 if (hcom == INVALID_HANDLE_VALUE) return;
2034
2035 ret = GetCommState(hcom, &dcb);
2036 ok(ret, "GetCommState error %d\n", GetLastError());
2037 dcb.BaudRate = 9600;
2038 dcb.ByteSize = 8;
2039 dcb.Parity = NOPARITY;
2040 dcb.fRtsControl = RTS_CONTROL_ENABLE;
2041 dcb.fDtrControl = DTR_CONTROL_ENABLE;
2042 dcb.StopBits = ONESTOPBIT;
2043 ret = SetCommState(hcom, &dcb);
2044 ok(ret, "SetCommState error %d\n", GetLastError());
2045
2046 memset(&timeouts, 0, sizeof(timeouts));
2047 timeouts.ReadTotalTimeoutConstant = TIMEOUT;
2048 ret = SetCommTimeouts(hcom, &timeouts);
2049 ok(ret,"SetCommTimeouts error %d\n", GetLastError());
2050
2051 ret = SetupComm(hcom, 1024, 1024);
2052 ok(ret, "SetUpComm error %d\n", GetLastError());
2053
2054 bytes = 0xdeadbeef;
2055 SetLastError(0xdeadbeef);
2056 ret = WriteFile(hcom, atz, 0, &bytes, NULL);
2057 ok(!ret, "WriteFile should fail\n");
2058 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2059 ok(bytes == 0, "bytes %u\n", bytes);
2060
2061 U(iob).Status = -1;
2062 iob.Information = -1;
2063 status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, NULL, NULL);
2064 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status);
2065 ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
2066 ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information);
2067
2068 for (i = -20; i < 20; i++)
2069 {
2070 U(iob).Status = -1;
2071 iob.Information = -1;
2072 offset.QuadPart = (LONGLONG)i;
2073 status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, 0, &offset, NULL);
2074 if (i >= 0 || i == -1)
2075 {
2076 ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status);
2077 ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status);
2078 ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information);
2079 }
2080 else
2081 {
2082 ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status);
2083 ok(U(iob).Status == -1, "%d: expected -1, got %#x\n", i, U(iob).Status);
2084 ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information);
2085 }
2086 }
2087
2088 U(iob).Status = -1;
2089 iob.Information = -1;
2090 offset.QuadPart = 0;
2091 status = pNtWriteFile(hcom, 0, NULL, NULL, &iob, atz, sizeof(atz), &offset, NULL);
2092 ok(status == STATUS_PENDING || status == STATUS_SUCCESS, "expected STATUS_PENDING or STATUS_SUCCESS, got %#x\n", status);
2093 /* Under Windows checking IO_STATUS_BLOCK right after the call leads
2094 * to races, iob.Status is either -1 or STATUS_SUCCESS, which means
2095 * that it's set only when the operation completes.
2096 */
2097 ret = WaitForSingleObject(hcom, TIMEOUT);
2098 if (ret == WAIT_TIMEOUT)
2099 {
2100 skip("Probably modem is not connected.\n");
2101 CloseHandle(hcom);
2102 return;
2103 }
2104 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject error %d\n", ret);
2105 ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status);
2106 ok(iob.Information == sizeof(atz), "expected sizeof(atz), got %lu\n", iob.Information);
2107
2108 ret = SetCommMask(hcom, EV_RXCHAR);
2109 ok(ret, "SetCommMask error %d\n", GetLastError());
2110
2111 S(U(ovl_wait)).Offset = 0;
2112 S(U(ovl_wait)).OffsetHigh = 0;
2113 ovl_wait.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
2114
2115 trace("waiting 3 secs for modem response...\n");
2116 last_event_time = 0;
2117 before = GetTickCount();
2118 do
2119 {
2120 evtmask = 0;
2121 SetLastError(0xdeadbeef);
2122 ret = WaitCommEvent(hcom, &evtmask, &ovl_wait);
2123 ok(!ret && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent returned %d, error %d\n", ret, GetLastError());
2124 if (GetLastError() != ERROR_IO_PENDING) goto done; /* no point in further testing */
2125 for (;;)
2126 {
2127 ret = WaitForSingleObject(ovl_wait.hEvent, 100);
2128 after = GetTickCount();
2129 if (ret == WAIT_OBJECT_0)
2130 {
2131 trace("got modem response.\n");
2132
2133 last_event_time = after;
2134 ret = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
2135 ok(ret, "GetOverlappedResult reported error %d\n", GetLastError());
2136 ok(bytes == sizeof(evtmask), "expected sizeof(evtmask), got %u\n", bytes);
2137 ok(evtmask & EV_RXCHAR, "EV_RXCHAR should be set\n");
2138
2139 bytes = 0xdeadbeef;
2140 SetLastError(0xdeadbeef);
2141 ret = ReadFile(hcom, buf, 0, &bytes, NULL);
2142 ok(!ret, "ReadFile should fail\n");
2143 ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
2144 ok(bytes == 0, "bytes %u\n", bytes);
2145
2146 U(iob).Status = -1;
2147 iob.Information = -1;
2148 status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, NULL, NULL);
2149 ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got %#x\n", status);
2150 ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
2151 ok(iob.Information == -1, "expected -1, got %ld\n", iob.Information);
2152
2153 for (i = -20; i < 20; i++)
2154 {
2155 U(iob).Status = -1;
2156 iob.Information = -1;
2157 offset.QuadPart = (LONGLONG)i;
2158 status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 0, &offset, NULL);
2159 if (i >= 0)
2160 {
2161 ok(status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, status);
2162 ok(U(iob).Status == STATUS_SUCCESS, "%d: expected STATUS_SUCCESS, got %#x\n", i, U(iob).Status);
2163 ok(iob.Information == 0, "%d: expected 0, got %lu\n", i, iob.Information);
2164 }
2165 else
2166 {
2167 ok(status == STATUS_INVALID_PARAMETER, "%d: expected STATUS_INVALID_PARAMETER, got %#x\n", i, status);
2168 ok(U(iob).Status == -1, "%d: expected -1, got %#x\n", i, U(iob).Status);
2169 ok(iob.Information == -1, "%d: expected -1, got %ld\n", i, iob.Information);
2170 }
2171 }
2172
2173 U(iob).Status = -1;
2174 iob.Information = -1;
2175 offset.QuadPart = 0;
2176 status = pNtReadFile(hcom, 0, NULL, NULL, &iob, buf, 1, &offset, NULL);
2177 ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", status);
2178 ok(U(iob).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x\n", U(iob).Status);
2179 ok(iob.Information == 1, "expected 1, got %lu\n", iob.Information);
2180 goto done;
2181 }
2182 else
2183 {
2184 if (last_event_time || after - before >= 3000) goto done;
2185 }
2186 }
2187 } while (after - before < 3000);
2188
2189 done:
2190 CloseHandle(ovl_wait.hEvent);
2191 CloseHandle(hcom);
2192 }
2193
2194 START_TEST(comm)
2195 {
2196 HMODULE ntdll = GetModuleHandleA("ntdll.dll");
2197 if (ntdll)
2198 {
2199 pNtReadFile = (void *)GetProcAddress(ntdll, "NtReadFile");
2200 pNtWriteFile = (void *)GetProcAddress(ntdll, "NtWriteFile");
2201 }
2202
2203 test_ClearCommError(); /* keep it the very first test */
2204 test_FlushFileBuffers();
2205 test_BuildCommDCB();
2206 test_ReadTimeOut();
2207 test_waittxempty();
2208 test_non_pending_errors();
2209 test_LoopbackRead();
2210 test_LoopbackCtsRts();
2211 test_LoopbackDtrDsr();
2212 test_LoopbackDtrRing();
2213 test_LoopbackDtrDcd();
2214 test_WaitRx();
2215 test_WaitCts();
2216 test_AbortWaitCts();
2217 test_WaitDsr();
2218 test_WaitRing();
2219 test_WaitDcd();
2220 test_WaitBreak();
2221 test_stdio();
2222 test_read_write();
2223
2224 if (!winetest_interactive)
2225 {
2226 skip("interactive tests (set WINETEST_INTERACTIVE=1)\n");
2227 return;
2228 }
2229
2230 test_WaitCommEvent();
2231 }