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