comctl32: We can now store binary files in the repository.
[wine] / dlls / localspl / tests / localmon.c
1 /* 
2  * Unit test suite for localspl API functions: local print monitor
3  *
4  * Copyright 2006-2007 Detlef Riekenberg
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
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wingdi.h"
28 #include "winreg.h"
29
30 #include "winspool.h"
31 #include "ddk/winsplp.h"
32
33 #include "wine/test.h"
34
35
36 /* ##### */
37
38 static HMODULE  hdll;
39 static HMODULE  hlocalmon;
40 static LPMONITOREX (WINAPI *pInitializePrintMonitor)(LPWSTR);
41
42 static LPMONITOREX pm;
43 static BOOL  (WINAPI *pEnumPorts)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
44 static BOOL  (WINAPI *pOpenPort)(LPWSTR, PHANDLE);
45 static BOOL  (WINAPI *pOpenPortEx)(LPWSTR, LPWSTR, PHANDLE, struct _MONITOR *);
46 static BOOL  (WINAPI *pStartDocPort)(HANDLE, LPWSTR, DWORD, DWORD, LPBYTE);
47 static BOOL  (WINAPI *pWritePort)(HANDLE hPort, LPBYTE, DWORD, LPDWORD);
48 static BOOL  (WINAPI *pReadPort)(HANDLE hPort, LPBYTE, DWORD, LPDWORD);
49 static BOOL  (WINAPI *pEndDocPort)(HANDLE);
50 static BOOL  (WINAPI *pClosePort)(HANDLE);
51 static BOOL  (WINAPI *pAddPort)(LPWSTR, HWND, LPWSTR);
52 static BOOL  (WINAPI *pAddPortEx)(LPWSTR, DWORD, LPBYTE, LPWSTR);
53 static BOOL  (WINAPI *pConfigurePort)(LPWSTR, HWND, LPWSTR);
54 static BOOL  (WINAPI *pDeletePort)(LPWSTR, HWND, LPWSTR);
55 static BOOL  (WINAPI *pGetPrinterDataFromPort)(HANDLE, DWORD, LPWSTR, LPWSTR, DWORD, LPWSTR, DWORD, LPDWORD);
56 static BOOL  (WINAPI *pSetPortTimeOuts)(HANDLE, LPCOMMTIMEOUTS, DWORD);
57 static BOOL  (WINAPI *pXcvOpenPort)(LPCWSTR, ACCESS_MASK, PHANDLE phXcv);
58 static DWORD (WINAPI *pXcvDataPort)(HANDLE, LPCWSTR, PBYTE, DWORD, PBYTE, DWORD, PDWORD);
59 static BOOL  (WINAPI *pXcvClosePort)(HANDLE);
60
61 static HANDLE hXcv;
62 static HANDLE hXcv_noaccess;
63
64 /* ########################### */
65
66 static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0};
67 static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e',
68                                     'L','P','T','P','o','r','t',
69                                     'C','o','m','m','a','n','d','O','K',0};
70 static WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
71 static WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t',
72                                     'T','r','a','n','s','m','i','s','s','i','o','n',
73                                     'R','e','t','r','y','T','i','m','e','o','u','t',0};
74
75 static WCHAR cmd_MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
76 static WCHAR cmd_MonitorUI_lcaseW[] = {'m','o','n','i','t','o','r','u','i',0};
77 static WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
78 static WCHAR does_not_existW[] = {'d','o','e','s','_','n','o','t','_','e','x','i','s','t',0};
79 static CHAR  emptyA[] = "";
80 static WCHAR emptyW[] = {0};
81 static WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
82 static WCHAR Monitors_LocalPortW[] = {
83                                 'S','y','s','t','e','m','\\',
84                                 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
85                                 'C','o','n','t','r','o','l','\\',
86                                 'P','r','i','n','t','\\',
87                                 'M','o','n','i','t','o','r','s','\\',
88                                 'L','o','c','a','l',' ','P','o','r','t',0};
89
90 static CHAR  num_0A[] = "0";
91 static WCHAR num_0W[] = {'0',0};
92 static CHAR  num_1A[] = "1";
93 static WCHAR num_1W[] = {'1',0};
94 static CHAR  num_999999A[] = "999999";
95 static WCHAR num_999999W[] = {'9','9','9','9','9','9',0};
96 static CHAR  num_1000000A[] = "1000000";
97 static WCHAR num_1000000W[] = {'1','0','0','0','0','0','0',0};
98
99 static WCHAR portname_comW[]  = {'C','O','M',0};
100 static WCHAR portname_com1W[] = {'C','O','M','1',':',0};
101 static WCHAR portname_com2W[] = {'C','O','M','2',':',0};
102 static WCHAR portname_fileW[] = {'F','I','L','E',':',0};
103 static WCHAR portname_lptW[]  = {'L','P','T',0};
104 static WCHAR portname_lpt1W[] = {'L','P','T','1',':',0};
105 static WCHAR portname_lpt2W[] = {'L','P','T','2',':',0};
106 static WCHAR server_does_not_existW[] = {'\\','\\','d','o','e','s','_','n','o','t','_','e','x','i','s','t',0};
107
108 static CHAR  TransmissionRetryTimeoutA[] = {'T','r','a','n','s','m','i','s','s','i','o','n',
109                                     'R','e','t','r','y','T','i','m','e','o','u','t',0};
110
111 static CHAR  WinNT_CV_WindowsA[] = {'S','o','f','t','w','a','r','e','\\',
112                                     'M','i','c','r','o','s','o','f','t','\\',
113                                     'W','i','n','d','o','w','s',' ','N','T','\\',
114                                     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
115                                     'W','i','n','d','o','w','s',0};
116 static WCHAR wineW[] = {'W','i','n','e',0};
117
118 static WCHAR tempdirW[MAX_PATH];
119 static WCHAR tempfileW[MAX_PATH];
120
121 #define PORTNAME_PREFIX  3
122 #define PORTNAME_MINSIZE 5
123 #define PORTNAME_MAXSIZE 10
124 static WCHAR have_com[PORTNAME_MAXSIZE];
125 static WCHAR have_lpt[PORTNAME_MAXSIZE];
126 static WCHAR have_file[PORTNAME_MAXSIZE];
127
128 /* ########################### */
129
130 static DWORD delete_port(LPWSTR portname)
131 {
132     DWORD   res;
133
134     if (pDeletePort) {
135         res = pDeletePort(NULL, 0, portname);
136     }
137     else
138     {
139         res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) portname, (lstrlenW(portname) + 1) * sizeof(WCHAR), NULL, 0, NULL);
140     }
141     return res;
142 }
143
144 /* ########################### */
145
146 static void find_installed_ports(void)
147 {
148     PORT_INFO_1W * pi = NULL;
149     WCHAR   nameW[PORTNAME_MAXSIZE];
150     DWORD   needed;
151     DWORD   returned;
152     DWORD   res;
153     DWORD   id;
154
155     have_com[0] = '\0';
156     have_lpt[0] = '\0';
157     have_file[0] = '\0';
158
159     if (!pEnumPorts) return;
160
161     res = pEnumPorts(NULL, 1, NULL, 0, &needed, &returned);
162     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
163         pi = HeapAlloc(GetProcessHeap(), 0, needed);
164     }
165     res = pEnumPorts(NULL, 1, (LPBYTE) pi, needed, &needed, &returned);
166
167     if (!res) {
168         skip("no ports found\n");
169         return;
170     }
171
172     id = 0;
173     while (id < returned) {
174         res = lstrlenW(pi[id].pName);
175         if ((res >= PORTNAME_MINSIZE) && (res < PORTNAME_MAXSIZE) &&
176             (pi[id].pName[res-1] == ':')) {
177             /* copy only the prefix ("LPT" or "COM") */
178             memcpy(&nameW, pi[id].pName, PORTNAME_PREFIX * sizeof(WCHAR));
179             nameW[PORTNAME_PREFIX] = '\0';
180
181             if (!have_com[0] && (lstrcmpiW(nameW, portname_comW) == 0)) {
182                 memcpy(&have_com, pi[id].pName, (res+1) * sizeof(WCHAR));
183             }
184
185             if (!have_lpt[0] && (lstrcmpiW(nameW, portname_lptW) == 0)) {
186                 memcpy(&have_lpt, pi[id].pName, (res+1) * sizeof(WCHAR));
187             }
188
189             if (!have_file[0] && (lstrcmpiW(pi[id].pName, portname_fileW) == 0)) {
190                 memcpy(&have_file, pi[id].pName, (res+1) * sizeof(WCHAR));
191             }
192         }
193         id++;
194     }
195
196     HeapFree(GetProcessHeap(), 0, pi);
197 }
198
199 /* ########################### */
200
201 static void test_AddPort(void)
202 {
203     DWORD   res;
204
205     /* moved to localui.dll since w2k */
206     if (!pAddPort) return;
207
208     if (0)
209     {
210     /* NT4 crash on this test */
211     res = pAddPort(NULL, 0, NULL);
212     }
213
214     /*  Testing-Results (localmon.dll from NT4.0):
215         - The Servername is ignored
216         - Case of MonitorName is ignored
217     */
218
219     SetLastError(0xdeadbeef);
220     res = pAddPort(NULL, 0, emptyW);
221     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
222
223     SetLastError(0xdeadbeef);
224     res = pAddPort(NULL, 0, does_not_existW);
225     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
226
227 }
228
229 /* ########################### */
230
231 static void test_AddPortEx(void)
232 {
233     PORT_INFO_2W pi;
234     DWORD   res;
235
236     if (!pAddPortEx) {
237         skip("AddPortEx\n");
238         return;
239     }
240     if ((!pDeletePort) &&  (!hXcv)) {
241         skip("No API to delete a Port\n");
242         return;
243     }
244
245     /* start test with clean ports */
246     delete_port(tempfileW);
247
248     pi.pPortName = tempfileW;
249     if (0) {
250         /* tests crash with native localspl.dll in w2k,
251            but works with native localspl.dll in wine */
252         SetLastError(0xdeadbeef);
253         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
254         trace("returned %u with %u\n", res, GetLastError() );
255         ok( res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
256
257         /* port already exists: */
258         SetLastError(0xdeadbeef);
259         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
260         trace("returned %u with %u\n", res, GetLastError() );
261         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
262             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
263             res, GetLastError());
264         delete_port(tempfileW);
265
266
267         /*  NULL for pMonitorName is documented for Printmonitors, but
268             localspl.dll fails always with ERROR_INVALID_PARAMETER  */
269         SetLastError(0xdeadbeef);
270         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, NULL);
271         trace("returned %u with %u\n", res, GetLastError() );
272         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
273             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
274             res, GetLastError());
275         if (res) delete_port(tempfileW);
276
277
278         SetLastError(0xdeadbeef);
279         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, emptyW);
280         trace("returned %u with %u\n", res, GetLastError() );
281         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
282             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
283             res, GetLastError());
284         if (res) delete_port(tempfileW);
285
286
287         SetLastError(0xdeadbeef);
288         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, does_not_existW);
289         trace("returned %u with %u\n", res, GetLastError() );
290         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
291             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
292             res, GetLastError());
293         if (res) delete_port(tempfileW);
294     }
295
296     pi.pPortName = NULL;
297     SetLastError(0xdeadbeef);
298     res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
299     ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
300         "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
301         res, GetLastError());
302
303     /*  level 2 is documented as supported for Printmonitors,
304         but localspl.dll fails always with ERROR_INVALID_LEVEL */
305
306     pi.pPortName = tempfileW;
307     pi.pMonitorName = LocalPortW;
308     pi.pDescription = wineW;
309     pi.fPortType = PORT_TYPE_WRITE;
310
311     SetLastError(0xdeadbeef);
312     res = pAddPortEx(NULL, 2, (LPBYTE) &pi, LocalPortW);
313     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
314         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
315         res, GetLastError());
316     if (res) delete_port(tempfileW);
317
318
319     /* invalid levels */
320     SetLastError(0xdeadbeef);
321     res = pAddPortEx(NULL, 0, (LPBYTE) &pi, LocalPortW);
322     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
323         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
324         res, GetLastError());
325     if (res) delete_port(tempfileW);
326
327
328     SetLastError(0xdeadbeef);
329     res = pAddPortEx(NULL, 3, (LPBYTE) &pi, LocalPortW);
330     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
331         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
332         res, GetLastError());
333     if (res) delete_port(tempfileW);
334
335     /* cleanup */
336     delete_port(tempfileW);
337 }
338
339 /* ########################### */
340
341 static void test_ClosePort()
342 {
343     HANDLE  hPort;
344     HANDLE  hPort2;
345     LPWSTR  nameW = NULL;
346     DWORD   res;
347     DWORD   res2;
348
349
350     if (!pOpenPort || !pClosePort) return;
351
352     if (have_com[0]) {
353         nameW = have_com;
354
355         hPort = (HANDLE) 0xdeadbeef;
356         res = pOpenPort(nameW, &hPort);
357         hPort2 = (HANDLE) 0xdeadbeef;
358         res2 = pOpenPort(nameW, &hPort2);
359
360         if (res2 && (hPort2 != hPort)) {
361             SetLastError(0xdeadbeef);
362             res2 = pClosePort(hPort2);
363             ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError());
364         }
365
366         if (res) {
367             SetLastError(0xdeadbeef);
368             res = pClosePort(hPort);
369             ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
370         }
371     }
372
373
374     if (have_lpt[0]) {
375         nameW = have_lpt;
376
377         hPort = (HANDLE) 0xdeadbeef;
378         res = pOpenPort(nameW, &hPort);
379         hPort2 = (HANDLE) 0xdeadbeef;
380         res2 = pOpenPort(nameW, &hPort2);
381
382         if (res2 && (hPort2 != hPort)) {
383             SetLastError(0xdeadbeef);
384             res2 = pClosePort(hPort2);
385             ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError());
386         }
387
388         if (res) {
389             SetLastError(0xdeadbeef);
390             res = pClosePort(hPort);
391             ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
392         }
393     }
394
395
396     if (have_file[0]) {
397         nameW = have_file;
398
399         hPort = (HANDLE) 0xdeadbeef;
400         res = pOpenPort(nameW, &hPort);
401         hPort2 = (HANDLE) 0xdeadbeef;
402         res2 = pOpenPort(nameW, &hPort2);
403
404         if (res2 && (hPort2 != hPort)) {
405             SetLastError(0xdeadbeef);
406             res2 = pClosePort(hPort2);
407             ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError());
408         }
409
410         if (res) {
411             SetLastError(0xdeadbeef);
412             res = pClosePort(hPort);
413             ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
414         }
415
416     }
417
418     if (0) {
419         /* an invalid HANDLE crash native localspl.dll */
420
421         SetLastError(0xdeadbeef);
422         res = pClosePort(NULL);
423         trace("got %u with %u\n", res, GetLastError());
424
425         SetLastError(0xdeadbeef);
426         res = pClosePort( (HANDLE) 0xdeadbeef);
427         trace("got %u with %u\n", res, GetLastError());
428
429         SetLastError(0xdeadbeef);
430         res = pClosePort(INVALID_HANDLE_VALUE);
431         trace("got %u with %u\n", res, GetLastError());
432     }
433
434 }
435
436 /* ########################### */
437                                        
438 static void test_ConfigurePort(void)
439 {
440     DWORD   res;
441
442     /* moved to localui.dll since w2k */
443     if (!pConfigurePort) return;
444
445     if (0)
446     {
447     /* NT4 crash on this test */
448     res = pConfigurePort(NULL, 0, NULL);
449     }
450
451     /*  Testing-Results (localmon.dll from NT4.0):
452         - Case of Portname is ignored
453         - "COM1:" and "COM01:" are the same (Compared by value)
454         - Portname without ":" => Dialog "Nothing to configure" comes up; Success
455         - "LPT1:", "LPT0:" and "LPT:" are the same (Numbers in "LPT:" are ignored)
456         - Empty Servername (LPT1:) => Dialog comes up (Servername is ignored)
457         - "FILE:" => Dialog "Nothing to configure" comes up; Success
458         - Empty Portname =>  => Dialog "Nothing to configure" comes up; Success
459         - Port "does_not_exist" => Dialog "Nothing to configure" comes up; Success
460     */
461     if (winetest_interactive > 0) {
462
463         SetLastError(0xdeadbeef);
464         res = pConfigurePort(NULL, 0, portname_com1W);
465         trace("returned %d with %u\n", res, GetLastError());
466
467         SetLastError(0xdeadbeef);
468         res = pConfigurePort(NULL, 0, portname_lpt1W);
469         trace("returned %d with %u\n", res, GetLastError());
470
471         SetLastError(0xdeadbeef);
472         res = pConfigurePort(NULL, 0, portname_fileW);
473         trace("returned %d with %u\n", res, GetLastError());
474     }
475 }
476
477 /* ########################### */
478
479 static void test_DeletePort(void)
480 {
481     DWORD   res;
482
483     /* moved to localui.dll since w2k */
484     if (!pDeletePort) return;
485
486     if (0)
487     {
488     /* NT4 crash on this test */
489     res = pDeletePort(NULL, 0, NULL);
490     }
491
492     /*  Testing-Results (localmon.dll from NT4.0):
493         - Case of Portname is ignored (returned '1' on Success)
494         - "COM1:" and "COM01:" are different (Compared as string)
495         - server_does_not_exist (LPT1:) => Port deleted, Success (Servername is ignored)
496         - Empty Portname =>  => FALSE (LastError not changed)
497         - Port "does_not_exist" => FALSE (LastError not changed)
498     */
499
500     SetLastError(0xdeadbeef);
501     res = pDeletePort(NULL, 0, emptyW);
502     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
503
504     SetLastError(0xdeadbeef);
505     res = pDeletePort(NULL, 0, does_not_existW);
506     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
507
508 }
509
510 /* ########################### */
511
512 static void test_EnumPorts(void)
513 {
514     DWORD   res;
515     DWORD   level;
516     LPBYTE  buffer;
517     DWORD   cbBuf;
518     DWORD   pcbNeeded;
519     DWORD   pcReturned;
520
521     if (!pEnumPorts) return;
522
523     /* valid levels are 1 and 2 */
524     for(level = 0; level < 4; level++) {
525
526         cbBuf = 0xdeadbeef;
527         pcReturned = 0xdeadbeef;
528         SetLastError(0xdeadbeef);
529         res = pEnumPorts(NULL, level, NULL, 0, &cbBuf, &pcReturned);
530
531         /* use only a short test, when we test with an invalid level */
532         if(!level || (level > 2)) {
533             /* NT4 fails with ERROR_INVALID_LEVEL (as expected)
534                XP succeeds with ERROR_SUCCESS () */
535             ok( (cbBuf == 0) && (pcReturned == 0),
536                 "(%d) returned %d with %u and %d, %d (expected 0, 0)\n",
537                 level, res, GetLastError(), cbBuf, pcReturned);
538             continue;
539         }        
540
541         ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
542             "(%d) returned %d with %u and %d, %d (expected '0' with "
543             "ERROR_INSUFFICIENT_BUFFER)\n",
544             level, res, GetLastError(), cbBuf, pcReturned);
545
546         buffer = HeapAlloc(GetProcessHeap(), 0, cbBuf * 2);
547         if (buffer == NULL) continue;
548
549         pcbNeeded = 0xdeadbeef;
550         pcReturned = 0xdeadbeef;
551         SetLastError(0xdeadbeef);
552         res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, &pcReturned);
553         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
554             level, res, GetLastError(), pcbNeeded, pcReturned);
555         /* We can compare the returned Data with the Registry / "win.ini",[Ports] here */
556
557         pcbNeeded = 0xdeadbeef;
558         pcReturned = 0xdeadbeef;
559         SetLastError(0xdeadbeef);
560         res = pEnumPorts(NULL, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
561         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
562             level, res, GetLastError(), pcbNeeded, pcReturned);
563
564         pcbNeeded = 0xdeadbeef;
565         pcReturned = 0xdeadbeef;
566         SetLastError(0xdeadbeef);
567         res = pEnumPorts(NULL, level, buffer, cbBuf-1, &pcbNeeded, &pcReturned);
568         ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
569             "(%d) returned %d with %u and %d, %d (expected '0' with "
570             "ERROR_INSUFFICIENT_BUFFER)\n",
571             level, res, GetLastError(), pcbNeeded, pcReturned);
572
573         if (0)
574         {
575         /* The following tests crash this app with native localmon/localspl */
576         res = pEnumPorts(NULL, level, NULL, cbBuf, &pcbNeeded, &pcReturned);
577         res = pEnumPorts(NULL, level, buffer, cbBuf, NULL, &pcReturned);
578         res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, NULL);
579         }
580
581         /* The Servername is ignored */
582         pcbNeeded = 0xdeadbeef;
583         pcReturned = 0xdeadbeef;
584         SetLastError(0xdeadbeef);
585         res = pEnumPorts(emptyW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
586         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
587             level, res, GetLastError(), pcbNeeded, pcReturned);
588
589         pcbNeeded = 0xdeadbeef;
590         pcReturned = 0xdeadbeef;
591         SetLastError(0xdeadbeef);
592         res = pEnumPorts(server_does_not_existW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
593         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
594             level, res, GetLastError(), pcbNeeded, pcReturned);
595
596         HeapFree(GetProcessHeap(), 0, buffer);
597     }
598 }
599
600 /* ########################### */
601
602
603 static void test_InitializePrintMonitor(void)
604 {
605     LPMONITOREX res;
606
607     SetLastError(0xdeadbeef);
608     res = pInitializePrintMonitor(NULL);
609     /* The Parameter was unchecked before w2k */
610     ok( res || (GetLastError() == ERROR_INVALID_PARAMETER),
611         "returned %p with %u\n (expected '!= NULL' or: NULL with "
612         "ERROR_INVALID_PARAMETER)\n", res, GetLastError());
613
614     SetLastError(0xdeadbeef);
615     res = pInitializePrintMonitor(emptyW);
616     ok( res || (GetLastError() == ERROR_INVALID_PARAMETER),
617         "returned %p with %u\n (expected '!= NULL' or: NULL with "
618         "ERROR_INVALID_PARAMETER)\n", res, GetLastError());
619
620
621     /* Every call with a non-empty string returns the same Pointer */
622     SetLastError(0xdeadbeef);
623     res = pInitializePrintMonitor(Monitors_LocalPortW);
624     ok( res == pm,
625         "returned %p with %u (expected %p)\n", res, GetLastError(), pm);
626 }
627
628
629 /* ########################### */
630
631 static void test_OpenPort()
632 {
633     HANDLE  hPort;
634     HANDLE  hPort2;
635     LPWSTR  nameW = NULL;
636     DWORD   res;
637     DWORD   res2;
638
639     if (!pOpenPort || !pClosePort) return;
640
641     if (have_com[0]) {
642         nameW = have_com;
643
644         hPort = (HANDLE) 0xdeadbeef;
645         SetLastError(0xdeadbeef);
646         res = pOpenPort(nameW, &hPort);
647         ok( res, "got %u with %u and %p (expected '!= 0')\n",
648             res, GetLastError(), hPort);
649
650         /* the same HANDLE is returned for a second OpenPort in native localspl */
651         hPort2 = (HANDLE) 0xdeadbeef;
652         SetLastError(0xdeadbeef);
653         res2 = pOpenPort(nameW, &hPort2);
654         ok( res2, "got %u with %u and %p (expected '!= 0')\n",
655             res2, GetLastError(), hPort2);
656
657         if (res) pClosePort(hPort);
658         if (res2 && (hPort2 != hPort)) pClosePort(hPort2);
659     }
660
661     if (have_lpt[0]) {
662         nameW = have_lpt;
663
664         hPort = (HANDLE) 0xdeadbeef;
665         SetLastError(0xdeadbeef);
666         res = pOpenPort(nameW, &hPort);
667         ok( res || (GetLastError() == ERROR_ACCESS_DENIED),
668             "got %u with %u and %p (expected '!= 0' or '0' with ERROR_ACCESS_DENIED)\n",
669             res, GetLastError(), hPort);
670
671         /* the same HANDLE is returned for a second OpenPort in native localspl */
672         hPort2 = (HANDLE) 0xdeadbeef;
673         SetLastError(0xdeadbeef);
674         res2 = pOpenPort(nameW, &hPort2);
675         ok( res2 || (GetLastError() == ERROR_ACCESS_DENIED),
676             "got %u with %u and %p (expected '!= 0' or '0' with ERROR_ACCESS_DENIED)\n",
677             res2, GetLastError(), hPort2);
678
679         if (res) pClosePort(hPort);
680         if (res2 && (hPort2 != hPort)) pClosePort(hPort2);
681     }
682
683     if (have_file[0]) {
684         nameW = have_file;
685
686         hPort = (HANDLE) 0xdeadbeef;
687         SetLastError(0xdeadbeef);
688         res = pOpenPort(nameW, &hPort);
689         ok( res, "got %u with %u and %p (expected '!= 0')\n",
690             res, GetLastError(), hPort);
691
692         /* a different HANDLE is returned for a second OpenPort */
693         hPort2 = (HANDLE) 0xdeadbeef;
694         SetLastError(0xdeadbeef);
695         res2 = pOpenPort(nameW, &hPort2);
696         ok( res2 && (hPort2 != hPort),
697             "got %u with %u and %p (expected '!= 0' and '!= %p')\n",
698             res2, GetLastError(), hPort2, hPort);
699
700         if (res) pClosePort(hPort);
701         if (res2 && (hPort2 != hPort)) pClosePort(hPort2);
702     }
703
704     if (0) {
705         /* this test crash native localspl (w2k+xp) */
706         if (nameW) {
707             hPort = (HANDLE) 0xdeadbeef;
708             SetLastError(0xdeadbeef);
709             res = pOpenPort(nameW, NULL);
710             trace("got %u with %u and %p\n", res, GetLastError(), hPort);
711         }
712     }
713
714     hPort = (HANDLE) 0xdeadbeef;
715     SetLastError(0xdeadbeef);
716     res = pOpenPort(does_not_existW, &hPort);
717     ok (!res && (hPort == (HANDLE) 0xdeadbeef),
718         "got %u with 0x%x and %p (expectet '0' and 0xdeadbeef)\n", res, GetLastError(), hPort);
719     if (res) pClosePort(hPort);
720
721     hPort = (HANDLE) 0xdeadbeef;
722     SetLastError(0xdeadbeef);
723     res = pOpenPort(emptyW, &hPort);
724     ok (!res && (hPort == (HANDLE) 0xdeadbeef),
725         "got %u with 0x%x and %p (expectet '0' and 0xdeadbeef)\n", res, GetLastError(), hPort);
726     if (res) pClosePort(hPort);
727
728
729     /* NULL as name crash native localspl (w2k+xp) */
730     if (0) {
731         hPort = (HANDLE) 0xdeadbeef;
732         SetLastError(0xdeadbeef);
733         res = pOpenPort(NULL, &hPort);
734         trace("got %u with %u and %p\n", res, GetLastError(), hPort);
735     }
736
737 }
738
739 /* ########################### */
740
741 static void test_XcvClosePort(void)
742 {
743     DWORD   res;
744     HANDLE hXcv2;
745
746
747     if (0)
748     {
749     /* crash with native localspl.dll (w2k+xp) */
750     res = pXcvClosePort(NULL);
751     res = pXcvClosePort(INVALID_HANDLE_VALUE);
752     }
753
754
755     SetLastError(0xdeadbeef);
756     hXcv2 = (HANDLE) 0xdeadbeef;
757     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2);
758     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
759
760     if (res) {
761         SetLastError(0xdeadbeef);
762         res = pXcvClosePort(hXcv2);
763         ok( res, "returned %d with %u (expected '!= 0')\n", res, GetLastError());
764
765         if (0)
766         {
767         /* test for "Double Free": crash with native localspl.dll (w2k+xp) */
768         res = pXcvClosePort(hXcv2);
769         }
770     }
771 }
772
773 /* ########################### */
774
775 static void test_XcvDataPort_AddPort(void)
776 {
777     DWORD   res;
778
779
780     /*
781      * The following tests crash with native localspl.dll on w2k and xp,
782      * but it works, when the native dll (w2k and xp) is used in wine.
783      * also tested (same crash): replacing emptyW with portname_lpt1W
784      * and replacing "NULL, 0, NULL" with "buffer, MAX_PATH, &needed"
785      *
786      * We need to use a different API (AddPortEx) instead
787      */
788     if (0)
789     {
790     /* create a Port for a normal, writable file */
791     SetLastError(0xdeadbeef);
792     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
793
794     /* add our testport again */
795     SetLastError(0xdeadbeef);
796     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
797
798     /* create a well-known Port  */
799     SetLastError(0xdeadbeef);
800     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL);
801
802     SetLastError(0xdeadbeef);
803     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL);
804     /* native localspl.dll on wine: ERROR_ALREADY_EXISTS */
805
806     /* ERROR_ALREADY_EXISTS is also returned from native localspl.dll on wine,
807        when "RPT1:" was already installed for redmonnt.dll:
808        res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_rpt1W, ...
809     */
810
811     /* cleanup */
812     SetLastError(0xdeadbeef);
813     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
814     }
815
816 }
817
818 /* ########################### */
819
820 static void test_XcvDataPort_ConfigureLPTPortCommandOK(void)
821 {
822     CHAR    org_value[16];
823     CHAR    buffer[16];
824     HKEY    hroot = NULL;
825     DWORD   res;
826     DWORD   needed;
827
828
829     /* Read the original value from the registry */
830     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot);
831     if (res == ERROR_ACCESS_DENIED) {
832         skip("ACCESS_DENIED\n");
833         return;
834     }
835
836     if (res != ERROR_SUCCESS) {
837         /* unable to open the registry: skip the test */
838         skip("got %d\n", res);
839         return;
840     }
841     org_value[0] = '\0';
842     needed = sizeof(org_value)-1 ;
843     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed);
844     ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND),
845         "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or "
846         "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value);
847
848     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
849
850     /* set to "0" */
851     needed = (DWORD) 0xdeadbeef;
852     SetLastError(0xdeadbeef);
853     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_0W, sizeof(num_0W), NULL, 0, &needed);
854     if (res == ERROR_INVALID_PARAMETER) {
855         skip("'ConfigureLPTPortCommandOK' not supported\n");
856         return;
857     }
858     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
859     needed = sizeof(buffer)-1 ;
860     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
861     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_0A) == 0),
862         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
863         res, buffer, num_0A);
864
865
866     /* set to "1" */
867     needed = (DWORD) 0xdeadbeef;
868     SetLastError(0xdeadbeef);
869     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1W, sizeof(num_1W), NULL, 0, &needed);
870     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
871     needed = sizeof(buffer)-1 ;
872     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
873     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1A) == 0),
874         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
875         res, buffer, num_1A);
876
877     /* set to "999999" */
878     needed = (DWORD) 0xdeadbeef;
879     SetLastError(0xdeadbeef);
880     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_999999W, sizeof(num_999999W), NULL, 0, &needed);
881     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
882     needed = sizeof(buffer)-1 ;
883     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
884     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_999999A) == 0),
885         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
886         res, buffer, num_999999A);
887
888     /* set to "1000000" */
889     needed = (DWORD) 0xdeadbeef;
890     SetLastError(0xdeadbeef);
891     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1000000W, sizeof(num_1000000W), NULL, 0, &needed);
892     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
893     needed = sizeof(buffer)-1 ;
894     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
895     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1000000A) == 0),
896         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
897         res, buffer, num_1000000A);
898
899     /*  using cmd_ConfigureLPTPortCommandOKW with does_not_existW:
900         the string "does_not_exist" is written to the registry */
901
902
903     /* restore the original value */
904     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
905     if (org_value[0]) {
906         res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1);
907         ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value);
908     }
909
910     RegCloseKey(hroot);
911
912 }
913
914 /* ########################### */
915
916 static void test_XcvDataPort_DeletePort(void)
917 {
918     DWORD   res;
919     DWORD   needed;
920
921
922     /* cleanup: just to make sure */
923     needed = (DWORD) 0xdeadbeef;
924     SetLastError(0xdeadbeef);
925     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
926     ok( !res  || (res == ERROR_FILE_NOT_FOUND),
927         "returned %d with %u (expected ERROR_SUCCESS or ERROR_FILE_NOT_FOUND)\n",
928         res, GetLastError());
929
930
931     /* ToDo: cmd_AddPortW for tempfileW, then cmd_DeletePortW for the existing Port */
932
933
934     /* try to delete a nonexistent Port */
935     needed = (DWORD) 0xdeadbeef;
936     SetLastError(0xdeadbeef);
937     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
938     ok( res == ERROR_FILE_NOT_FOUND,
939         "returned %d with %u (expected ERROR_FILE_NOT_FOUND)\n", res, GetLastError());
940
941     /* emptyW as Portname: ERROR_FILE_NOT_FOUND is returned */
942     /* NULL as Portname: Native localspl.dll crashed */
943
944 }
945
946 /* ########################### */
947
948 static void test_XcvDataPort_GetTransmissionRetryTimeout(void)
949 {
950     CHAR    org_value[16];
951     HKEY    hroot = NULL;
952     DWORD   buffer[2];
953     DWORD   res;
954     DWORD   needed;
955     DWORD   len;
956
957
958     /* ask for needed size */
959     needed = (DWORD) 0xdeadbeef;
960     SetLastError(0xdeadbeef);
961     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, NULL, 0, &needed);
962     if (res == ERROR_INVALID_PARAMETER) {
963         skip("'GetTransmissionRetryTimeout' not supported\n");
964         return;
965     }
966     len = sizeof(DWORD);
967     ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed == len),
968         "returned %d with %u and %u (expected ERROR_INSUFFICIENT_BUFFER "
969         "and '%u')\n", res, GetLastError(), needed, len);
970     len = needed;
971
972     /* Read the original value from the registry */
973     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot);
974     if (res == ERROR_ACCESS_DENIED) {
975         skip("ACCESS_DENIED\n");
976         return;
977     }
978
979     if (res != ERROR_SUCCESS) {
980         /* unable to open the registry: skip the test */
981         skip("got %d\n", res);
982         return;
983     }
984
985     org_value[0] = '\0';
986     needed = sizeof(org_value)-1 ;
987     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed);
988     ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND),
989         "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or "
990         "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value);
991
992     /* Get default value (documented as 90 in the w2k reskit, but that is wrong) */
993     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
994     needed = (DWORD) 0xdeadbeef;
995     buffer[0] = 0xdeadbeef;
996     SetLastError(0xdeadbeef);
997     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
998     ok( (res == ERROR_SUCCESS) && (buffer[0] == 45),
999         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1000         "for '45')\n", res, GetLastError(), needed, buffer[0]);
1001
1002     /* the default timeout is returned, when the value is empty */
1003     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)emptyA, 1);
1004     needed = (DWORD) 0xdeadbeef;
1005     buffer[0] = 0xdeadbeef;
1006     SetLastError(0xdeadbeef);
1007     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1008     ok( (res == ERROR_SUCCESS) && (buffer[0] == 45),
1009         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1010         "for '45')\n", res, GetLastError(), needed, buffer[0]);
1011
1012     /* the dialog is limited (1 - 999999), but that is done somewhere else */
1013     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_0A, lstrlenA(num_0A)+1);
1014     needed = (DWORD) 0xdeadbeef;
1015     buffer[0] = 0xdeadbeef;
1016     SetLastError(0xdeadbeef);
1017     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1018     ok( (res == ERROR_SUCCESS) && (buffer[0] == 0),
1019         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1020         "for '0')\n", res, GetLastError(), needed, buffer[0]);
1021
1022
1023     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1A, lstrlenA(num_1A)+1);
1024     needed = (DWORD) 0xdeadbeef;
1025     buffer[0] = 0xdeadbeef;
1026     SetLastError(0xdeadbeef);
1027     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1028     ok( (res == ERROR_SUCCESS) && (buffer[0] == 1),
1029         "returned %d with %u and %u for %d\n (expected 'ERROR_SUCCESS' "
1030         "for '1')\n", res, GetLastError(), needed, buffer[0]);
1031
1032     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_999999A, lstrlenA(num_999999A)+1);
1033     needed = (DWORD) 0xdeadbeef;
1034     buffer[0] = 0xdeadbeef;
1035     SetLastError(0xdeadbeef);
1036     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1037     ok( (res == ERROR_SUCCESS) && (buffer[0] == 999999),
1038         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1039         "for '999999')\n", res, GetLastError(), needed, buffer[0]);
1040
1041
1042     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1000000A, lstrlenA(num_1000000A)+1);
1043     needed = (DWORD) 0xdeadbeef;
1044     buffer[0] = 0xdeadbeef;
1045     SetLastError(0xdeadbeef);
1046     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1047     ok( (res == ERROR_SUCCESS) && (buffer[0] == 1000000),
1048         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1049         "for '1000000')\n", res, GetLastError(), needed, buffer[0]);
1050
1051     /* restore the original value */
1052     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
1053     if (org_value[0]) {
1054         res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1);
1055         ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value);
1056     }
1057
1058     RegCloseKey(hroot);
1059 }
1060
1061 /* ########################### */
1062
1063 static void test_XcvDataPort_MonitorUI(void)
1064 {
1065     DWORD   res;
1066     BYTE    buffer[MAX_PATH + 2];
1067     DWORD   needed;
1068     DWORD   len;
1069
1070
1071     /* ask for needed size */
1072     needed = (DWORD) 0xdeadbeef;
1073     SetLastError(0xdeadbeef);
1074     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, 0, &needed);
1075     if (res == ERROR_INVALID_PARAMETER) {
1076         skip("'MonitorUI' nor supported\n");
1077         return;
1078     }
1079     ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed <= MAX_PATH),
1080         "returned %d with %u and 0x%x (expected 'ERROR_INSUFFICIENT_BUFFER' "
1081         " and '<= MAX_PATH')\n", res, GetLastError(), needed);
1082
1083     if (needed > MAX_PATH) {
1084         skip("buffer overflow (%u)\n", needed);
1085         return;
1086     }
1087     len = needed;
1088
1089     /* the command is required */
1090     needed = (DWORD) 0xdeadbeef;
1091     SetLastError(0xdeadbeef);
1092     res = pXcvDataPort(hXcv, emptyW, NULL, 0, NULL, 0, &needed);
1093     ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x "
1094         "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed);
1095
1096     if (0) {
1097     /* crash with native localspl.dll (w2k+xp) */
1098     res = pXcvDataPort(hXcv, NULL, NULL, 0, buffer, MAX_PATH, &needed);
1099     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, len, &needed);
1100     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, NULL);
1101     }
1102
1103
1104     /* hXcv is ignored for the command "MonitorUI" */
1105     needed = (DWORD) 0xdeadbeef;
1106     SetLastError(0xdeadbeef);
1107     res = pXcvDataPort(NULL, cmd_MonitorUIW, NULL, 0, buffer, len, &needed);
1108     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1109         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1110
1111
1112     /* pszDataName is case-sensitive */
1113     memset(buffer, 0, len);
1114     needed = (DWORD) 0xdeadbeef;
1115     SetLastError(0xdeadbeef);
1116     res = pXcvDataPort(hXcv, cmd_MonitorUI_lcaseW, NULL, 0, buffer, len, &needed);
1117     ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x "
1118         "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed);
1119
1120     /* off by one: larger  */
1121     needed = (DWORD) 0xdeadbeef;
1122     SetLastError(0xdeadbeef);
1123     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len+1, &needed);
1124     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1125         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1126
1127
1128     /* off by one: smaller */
1129     /* the buffer is not modified for NT4, w2k, XP */
1130     needed = (DWORD) 0xdeadbeef;
1131     SetLastError(0xdeadbeef);
1132     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len-1, &needed);
1133     ok( res == ERROR_INSUFFICIENT_BUFFER, "returned %d with %u and 0x%x "
1134         "(expected 'ERROR_INSUFFICIENT_BUFFER')\n", res, GetLastError(), needed);
1135
1136     /* Normal use. The DLL-Name without a Path is returned */
1137     memset(buffer, 0, len);
1138     needed = (DWORD) 0xdeadbeef;
1139     SetLastError(0xdeadbeef);
1140     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, &needed);
1141     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1142         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1143
1144
1145     /* small check without access-rights: */
1146     if (!hXcv_noaccess) return;
1147
1148     /* The ACCESS_MASK is ignored for "MonitorUI" */
1149     memset(buffer, 0, len);
1150     needed = (DWORD) 0xdeadbeef;
1151     SetLastError(0xdeadbeef);
1152     res = pXcvDataPort(hXcv_noaccess, cmd_MonitorUIW, NULL, 0, buffer, sizeof(buffer), &needed);
1153     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1154         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1155 }
1156
1157 /* ########################### */
1158
1159 static void test_XcvDataPort_PortIsValid(void)
1160 {
1161     DWORD   res;
1162     DWORD   needed;
1163
1164     /* normal use: "LPT1:" */
1165     needed = (DWORD) 0xdeadbeef;
1166     SetLastError(0xdeadbeef);
1167     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed);
1168     if (res == ERROR_INVALID_PARAMETER) {
1169         skip("'PostIsValid' not supported\n");
1170         return;
1171     }
1172     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1173
1174
1175     if (0) {
1176     /* crash with native localspl.dll (w2k+xp) */
1177     res = pXcvDataPort(hXcv, cmd_PortIsValidW, NULL, 0, NULL, 0, &needed);
1178     }
1179
1180
1181     /* hXcv is ignored for the command "PortIsValid" */
1182     needed = (DWORD) 0xdeadbeef;
1183     SetLastError(0xdeadbeef);
1184     res = pXcvDataPort(NULL, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL);
1185     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1186
1187     /* needed is ignored */
1188     needed = (DWORD) 0xdeadbeef;
1189     SetLastError(0xdeadbeef);
1190     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL);
1191     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1192
1193
1194     /* cbInputData is ignored */
1195     needed = (DWORD) 0xdeadbeef;
1196     SetLastError(0xdeadbeef);
1197     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 0, NULL, 0, &needed);
1198     ok( res == ERROR_SUCCESS,
1199         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1200         res, GetLastError(), needed);
1201
1202     needed = (DWORD) 0xdeadbeef;
1203     SetLastError(0xdeadbeef);
1204     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 1, NULL, 0, &needed);
1205     ok( res == ERROR_SUCCESS,
1206         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1207         res, GetLastError(), needed);
1208
1209     needed = (DWORD) 0xdeadbeef;
1210     SetLastError(0xdeadbeef);
1211     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -1, NULL, 0, &needed);
1212     ok( res == ERROR_SUCCESS,
1213         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1214         res, GetLastError(), needed);
1215
1216     needed = (DWORD) 0xdeadbeef;
1217     SetLastError(0xdeadbeef);
1218     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -2, NULL, 0, &needed);
1219     ok( res == ERROR_SUCCESS,
1220         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1221         res, GetLastError(), needed);
1222
1223
1224     /* an empty name is not allowed */
1225     needed = (DWORD) 0xdeadbeef;
1226     SetLastError(0xdeadbeef);
1227     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) emptyW, sizeof(emptyW), NULL, 0, &needed);
1228     ok( res == ERROR_PATH_NOT_FOUND,
1229         "returned %d with %u and 0x%x (expected ERROR_PATH_NOT_FOUND)\n",
1230         res, GetLastError(), needed);
1231
1232
1233     /* a directory is not allowed */
1234     needed = (DWORD) 0xdeadbeef;
1235     SetLastError(0xdeadbeef);
1236     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempdirW, (lstrlenW(tempdirW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1237     /* XP(admin): ERROR_INVALID_NAME, XP(user): ERROR_PATH_NOT_FOUND, w2k ERROR_ACCESS_DENIED */
1238     ok( (res == ERROR_INVALID_NAME) || (res == ERROR_PATH_NOT_FOUND) ||
1239         (res == ERROR_ACCESS_DENIED), "returned %d with %u and 0x%x "
1240         "(expected ERROR_INVALID_NAME, ERROR_PATH_NOT_FOUND or ERROR_ACCESS_DENIED)\n",
1241         res, GetLastError(), needed);
1242
1243
1244     /* test more valid well known Ports: */
1245     needed = (DWORD) 0xdeadbeef;
1246     SetLastError(0xdeadbeef);
1247     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt2W, sizeof(portname_lpt2W), NULL, 0, &needed);
1248     ok( res == ERROR_SUCCESS,
1249         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1250         res, GetLastError(), needed);
1251
1252
1253     needed = (DWORD) 0xdeadbeef;
1254     SetLastError(0xdeadbeef);
1255     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com1W, sizeof(portname_com1W), NULL, 0, &needed);
1256     ok( res == ERROR_SUCCESS,
1257         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1258         res, GetLastError(), needed);
1259
1260
1261     needed = (DWORD) 0xdeadbeef;
1262     SetLastError(0xdeadbeef);
1263     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com2W, sizeof(portname_com2W), NULL, 0, &needed);
1264     ok( res == ERROR_SUCCESS,
1265         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1266         res, GetLastError(), needed);
1267
1268
1269     needed = (DWORD) 0xdeadbeef;
1270     SetLastError(0xdeadbeef);
1271     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_fileW, sizeof(portname_fileW), NULL, 0, &needed);
1272     ok( res == ERROR_SUCCESS,
1273         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1274         res, GetLastError(), needed);
1275
1276
1277     /* a normal, writable file is allowed */
1278     needed = (DWORD) 0xdeadbeef;
1279     SetLastError(0xdeadbeef);
1280     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1281     ok( res == ERROR_SUCCESS,
1282         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1283         res, GetLastError(), needed);
1284
1285
1286     /* small check without access-rights: */
1287     if (!hXcv_noaccess) return;
1288
1289     /* The ACCESS_MASK from XcvOpenPort is ignored in "PortIsValid" */
1290     needed = (DWORD) 0xdeadbeef;
1291     SetLastError(0xdeadbeef);
1292     res = pXcvDataPort(hXcv_noaccess, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed);
1293     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1294
1295 }
1296
1297 /* ########################### */
1298
1299 static void test_XcvOpenPort(void)
1300 {
1301     DWORD   res;
1302     HANDLE  hXcv2;
1303
1304
1305     if (0)
1306     {
1307     /* crash with native localspl.dll (w2k+xp) */
1308     res = pXcvOpenPort(NULL, SERVER_ACCESS_ADMINISTER, &hXcv2);
1309     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, NULL);
1310     }
1311
1312
1313     /* The returned handle is the result from a previous "spoolss.dll,DllAllocSplMem" */
1314     SetLastError(0xdeadbeef);
1315     hXcv2 = (HANDLE) 0xdeadbeef;
1316     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2);
1317     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1318     if (res) pXcvClosePort(hXcv2);
1319
1320
1321     /* The ACCESS_MASK is not checked in XcvOpenPort */
1322     SetLastError(0xdeadbeef);
1323     hXcv2 = (HANDLE) 0xdeadbeef;
1324     res = pXcvOpenPort(emptyW, 0, &hXcv2);
1325     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1326     if (res) pXcvClosePort(hXcv2);
1327
1328
1329     /* A copy of pszObject is saved in the Memory-Block */
1330     SetLastError(0xdeadbeef);
1331     hXcv2 = (HANDLE) 0xdeadbeef;
1332     res = pXcvOpenPort(portname_lpt1W, SERVER_ALL_ACCESS, &hXcv2);
1333     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1334     if (res) pXcvClosePort(hXcv2);
1335
1336     SetLastError(0xdeadbeef);
1337     hXcv2 = (HANDLE) 0xdeadbeef;
1338     res = pXcvOpenPort(portname_fileW, SERVER_ALL_ACCESS, &hXcv2);
1339     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1340     if (res) pXcvClosePort(hXcv2);
1341
1342 }
1343
1344 /* ########################### */
1345
1346 #define GET_MONITOR_FUNC(name) \
1347             if(numentries > 0) { \
1348                 numentries--; \
1349                 p##name = (void *) pm->Monitor.pfn##name ;  \
1350             }
1351
1352
1353 START_TEST(localmon)
1354 {
1355     DWORD   numentries;
1356     DWORD   res;
1357
1358     /* This DLL does not exist on Win9x */
1359     hdll = LoadLibraryA("localspl.dll");
1360     if (!hdll) {
1361         skip("localspl.dll cannot be loaded, most likely running on Win9x\n");
1362         return;
1363     }
1364
1365     tempdirW[0] = '\0';
1366     tempfileW[0] = '\0';
1367     res = GetTempPathW(MAX_PATH, tempdirW);
1368     ok(res != 0, "with %u\n", GetLastError());
1369     res = GetTempFileNameW(tempdirW, wineW, 0, tempfileW);
1370     ok(res != 0, "with %u\n", GetLastError());
1371
1372     pInitializePrintMonitor = (void *) GetProcAddress(hdll, "InitializePrintMonitor");
1373
1374     if (!pInitializePrintMonitor) {
1375         /* The Monitor for "Local Ports" was in a separate dll before w2k */
1376         hlocalmon = LoadLibraryA("localmon.dll");
1377         if (hlocalmon) {
1378             pInitializePrintMonitor = (void *) GetProcAddress(hlocalmon, "InitializePrintMonitor");
1379         }
1380     }
1381     if (!pInitializePrintMonitor) return;
1382
1383     /* Native localmon.dll / localspl.dll need a valid Port-Entry in:
1384        a) since xp: HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports 
1385        b) up to w2k: Section "Ports" in win.ini
1386        or InitializePrintMonitor fails. */
1387     pm = pInitializePrintMonitor(Monitors_LocalPortW);
1388     if (pm) {
1389         numentries = (pm->dwMonitorSize ) / sizeof(VOID *);
1390         /* NT4: 14, since w2k: 17 */
1391         ok( numentries == 14 || numentries == 17, 
1392             "dwMonitorSize (%d) => %d Functions\n", pm->dwMonitorSize, numentries);
1393
1394         GET_MONITOR_FUNC(EnumPorts);
1395         GET_MONITOR_FUNC(OpenPort);
1396         GET_MONITOR_FUNC(OpenPortEx);
1397         GET_MONITOR_FUNC(StartDocPort);
1398         GET_MONITOR_FUNC(WritePort);
1399         GET_MONITOR_FUNC(ReadPort);
1400         GET_MONITOR_FUNC(EndDocPort);
1401         GET_MONITOR_FUNC(ClosePort);
1402         GET_MONITOR_FUNC(AddPort);
1403         GET_MONITOR_FUNC(AddPortEx);
1404         GET_MONITOR_FUNC(ConfigurePort);
1405         GET_MONITOR_FUNC(DeletePort);
1406         GET_MONITOR_FUNC(GetPrinterDataFromPort);
1407         GET_MONITOR_FUNC(SetPortTimeOuts);
1408         GET_MONITOR_FUNC(XcvOpenPort);
1409         GET_MONITOR_FUNC(XcvDataPort);
1410         GET_MONITOR_FUNC(XcvClosePort);
1411
1412         if ((pXcvOpenPort) && (pXcvDataPort) && (pXcvClosePort)) {
1413             SetLastError(0xdeadbeef);
1414             res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
1415             ok(res, "hXcv: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv);
1416
1417             SetLastError(0xdeadbeef);
1418             res = pXcvOpenPort(emptyW, 0, &hXcv_noaccess);
1419             ok(res, "hXcv_noaccess: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv_noaccess);
1420         }
1421     }
1422
1423     test_InitializePrintMonitor();
1424
1425     find_installed_ports();
1426
1427     test_AddPort();
1428     test_AddPortEx();
1429     test_ClosePort();
1430     test_ConfigurePort();
1431     test_DeletePort();
1432     test_EnumPorts();
1433     test_OpenPort();
1434
1435     if ( !hXcv ) {
1436         skip("Xcv not supported\n");
1437     }
1438     else
1439     {
1440         test_XcvClosePort();
1441         test_XcvDataPort_AddPort();
1442         test_XcvDataPort_ConfigureLPTPortCommandOK();
1443         test_XcvDataPort_DeletePort();
1444         test_XcvDataPort_GetTransmissionRetryTimeout();
1445         test_XcvDataPort_MonitorUI();
1446         test_XcvDataPort_PortIsValid();
1447         test_XcvOpenPort();
1448
1449         pXcvClosePort(hXcv);
1450     }
1451     if (hXcv_noaccess) pXcvClosePort(hXcv_noaccess);
1452
1453     /* Cleanup our temporary file */
1454     DeleteFileW(tempfileW);
1455 }