localspl/tests: Use skip if localspl can't be loaded.
[wine] / dlls / localspl / tests / localmon.c
1 /* 
2  * Unit test suite for localspl API functions: local print monitor
3  *
4  * Copyright 2006 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_com1W[] = {'C','O','M','1',':',0};
100 static WCHAR portname_com2W[] = {'C','O','M','2',':',0};
101 static WCHAR portname_fileW[] = {'F','I','L','E',':',0};
102 static WCHAR portname_lpt1W[] = {'L','P','T','1',':',0};
103 static WCHAR portname_lpt2W[] = {'L','P','T','2',':',0};
104 static WCHAR server_does_not_existW[] = {'\\','\\','d','o','e','s','_','n','o','t','_','e','x','i','s','t',0};
105
106 static CHAR  TransmissionRetryTimeoutA[] = {'T','r','a','n','s','m','i','s','s','i','o','n',
107                                     'R','e','t','r','y','T','i','m','e','o','u','t',0};
108
109 static CHAR  WinNT_CV_WindowsA[] = {'S','o','f','t','w','a','r','e','\\',
110                                     'M','i','c','r','o','s','o','f','t','\\',
111                                     'W','i','n','d','o','w','s',' ','N','T','\\',
112                                     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
113                                     'W','i','n','d','o','w','s',0};
114 static WCHAR wineW[] = {'W','i','n','e',0};
115
116 static WCHAR tempdirW[MAX_PATH];
117 static WCHAR tempfileW[MAX_PATH];
118
119
120 /* ########################### */
121
122 static DWORD delete_port(LPWSTR portname)
123 {
124     DWORD   res;
125
126     if (pDeletePort) {
127         res = pDeletePort(NULL, 0, portname);
128     }
129     else
130     {
131         res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) portname, (lstrlenW(portname) + 1) * sizeof(WCHAR), NULL, 0, NULL);
132     }
133     return res;
134 }
135
136 /* ########################### */
137
138 static void test_AddPort(void)
139 {
140     DWORD   res;
141
142     /* moved to localui.dll since w2k */
143     if (!pAddPort) return;
144
145     if (0)
146     {
147     /* NT4 crash on this test */
148     res = pAddPort(NULL, 0, NULL);
149     }
150
151     /*  Testing-Results (localmon.dll from NT4.0):
152         - The Servername is ignored
153         - Case of MonitorName is ignored
154     */
155
156     SetLastError(0xdeadbeef);
157     res = pAddPort(NULL, 0, emptyW);
158     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
159
160     SetLastError(0xdeadbeef);
161     res = pAddPort(NULL, 0, does_not_existW);
162     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
163
164 }
165
166 /* ########################### */
167
168 static void test_AddPortEx(void)
169 {
170     PORT_INFO_2W pi;
171     DWORD   res;
172
173     if (!pAddPortEx) {
174         skip("AddPortEx\n");
175         return;
176     }
177     if ((!pDeletePort) &&  (!hXcv)) {
178         skip("No API to delete a Port\n");
179         return;
180     }
181
182     /* start test with clean ports */
183     delete_port(tempfileW);
184
185     pi.pPortName = tempfileW;
186     if (0) {
187         /* tests crash with native localspl.dll in w2k,
188            but works with native localspl.dll in wine */
189         SetLastError(0xdeadbeef);
190         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
191         trace("returned %u with %u\n", res, GetLastError() );
192         ok( res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
193
194         /* port already exists: */
195         SetLastError(0xdeadbeef);
196         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
197         trace("returned %u with %u\n", res, GetLastError() );
198         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
199             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
200             res, GetLastError());
201         delete_port(tempfileW);
202
203
204         /*  NULL for pMonitorName is documented for Printmonitors, but
205             localspl.dll fails always with ERROR_INVALID_PARAMETER  */
206         SetLastError(0xdeadbeef);
207         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, NULL);
208         trace("returned %u with %u\n", res, GetLastError() );
209         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
210             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
211             res, GetLastError());
212         if (res) delete_port(tempfileW);
213
214
215         SetLastError(0xdeadbeef);
216         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, emptyW);
217         trace("returned %u with %u\n", res, GetLastError() );
218         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
219             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
220             res, GetLastError());
221         if (res) delete_port(tempfileW);
222
223
224         SetLastError(0xdeadbeef);
225         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, does_not_existW);
226         trace("returned %u with %u\n", res, GetLastError() );
227         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
228             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
229             res, GetLastError());
230         if (res) delete_port(tempfileW);
231     }
232
233     pi.pPortName = NULL;
234     SetLastError(0xdeadbeef);
235     res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
236     ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
237         "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
238         res, GetLastError());
239
240     /*  level 2 is documented as supported for Printmonitors,
241         but localspl.dll fails always with ERROR_INVALID_LEVEL */
242
243     pi.pPortName = tempfileW;
244     pi.pMonitorName = LocalPortW;
245     pi.pDescription = wineW;
246     pi.fPortType = PORT_TYPE_WRITE;
247
248     SetLastError(0xdeadbeef);
249     res = pAddPortEx(NULL, 2, (LPBYTE) &pi, LocalPortW);
250     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
251         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
252         res, GetLastError());
253     if (res) delete_port(tempfileW);
254
255
256     /* invalid levels */
257     SetLastError(0xdeadbeef);
258     res = pAddPortEx(NULL, 0, (LPBYTE) &pi, LocalPortW);
259     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
260         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
261         res, GetLastError());
262     if (res) delete_port(tempfileW);
263
264
265     SetLastError(0xdeadbeef);
266     res = pAddPortEx(NULL, 3, (LPBYTE) &pi, LocalPortW);
267     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
268         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
269         res, GetLastError());
270     if (res) delete_port(tempfileW);
271
272     /* cleanup */
273     delete_port(tempfileW);
274 }
275
276 /* ########################### */
277                                        
278 static void test_ConfigurePort(void)
279 {
280     DWORD   res;
281
282     /* moved to localui.dll since w2k */
283     if (!pConfigurePort) return;
284
285     if (0)
286     {
287     /* NT4 crash on this test */
288     res = pConfigurePort(NULL, 0, NULL);
289     }
290
291     /*  Testing-Results (localmon.dll from NT4.0):
292         - Case of Portname is ignored
293         - "COM1:" and "COM01:" are the same (Compared by value)
294         - Portname without ":" => Dialog "Nothing to configure" comes up; Success
295         - "LPT1:", "LPT0:" and "LPT:" are the same (Numbers in "LPT:" are ignored)
296         - Empty Servername (LPT1:) => Dialog comes up (Servername is ignored)
297         - "FILE:" => Dialog "Nothing to configure" comes up; Success
298         - Empty Portname =>  => Dialog "Nothing to configure" comes up; Success
299         - Port "does_not_exist" => Dialog "Nothing to configure" comes up; Success
300     */
301     if (winetest_interactive > 0) {
302
303         SetLastError(0xdeadbeef);
304         res = pConfigurePort(NULL, 0, portname_com1W);
305         trace("returned %d with %u\n", res, GetLastError());
306
307         SetLastError(0xdeadbeef);
308         res = pConfigurePort(NULL, 0, portname_lpt1W);
309         trace("returned %d with %u\n", res, GetLastError());
310
311         SetLastError(0xdeadbeef);
312         res = pConfigurePort(NULL, 0, portname_fileW);
313         trace("returned %d with %u\n", res, GetLastError());
314     }
315 }
316
317 /* ########################### */
318
319 static void test_DeletePort(void)
320 {
321     DWORD   res;
322
323     /* moved to localui.dll since w2k */
324     if (!pDeletePort) return;
325
326     if (0)
327     {
328     /* NT4 crash on this test */
329     res = pDeletePort(NULL, 0, NULL);
330     }
331
332     /*  Testing-Results (localmon.dll from NT4.0):
333         - Case of Portname is ignored (returned '1' on Success)
334         - "COM1:" and "COM01:" are different (Compared as string)
335         - server_does_not_exist (LPT1:) => Port deleted, Success (Servername is ignored)
336         - Empty Portname =>  => FALSE (LastError not changed)
337         - Port "does_not_exist" => FALSE (LastError not changed)
338     */
339
340     SetLastError(0xdeadbeef);
341     res = pDeletePort(NULL, 0, emptyW);
342     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
343
344     SetLastError(0xdeadbeef);
345     res = pDeletePort(NULL, 0, does_not_existW);
346     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
347
348 }
349
350 /* ########################### */
351
352 static void test_EnumPorts(void)
353 {
354     DWORD   res;
355     DWORD   level;
356     LPBYTE  buffer;
357     DWORD   cbBuf;
358     DWORD   pcbNeeded;
359     DWORD   pcReturned;
360
361     if (!pEnumPorts) return;
362
363     /* valid levels are 1 and 2 */
364     for(level = 0; level < 4; level++) {
365
366         cbBuf = 0xdeadbeef;
367         pcReturned = 0xdeadbeef;
368         SetLastError(0xdeadbeef);
369         res = pEnumPorts(NULL, level, NULL, 0, &cbBuf, &pcReturned);
370
371         /* use only a short test, when we test with an invalid level */
372         if(!level || (level > 2)) {
373             /* NT4 fails with ERROR_INVALID_LEVEL (as expected)
374                XP succeeds with ERROR_SUCCESS () */
375             ok( (cbBuf == 0) && (pcReturned == 0),
376                 "(%d) returned %d with %u and %d, %d (expected 0, 0)\n",
377                 level, res, GetLastError(), cbBuf, pcReturned);
378             continue;
379         }        
380
381         ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
382             "(%d) returned %d with %u and %d, %d (expected '0' with "
383             "ERROR_INSUFFICIENT_BUFFER)\n",
384             level, res, GetLastError(), cbBuf, pcReturned);
385
386         buffer = HeapAlloc(GetProcessHeap(), 0, cbBuf * 2);
387         if (buffer == NULL) continue;
388
389         pcbNeeded = 0xdeadbeef;
390         pcReturned = 0xdeadbeef;
391         SetLastError(0xdeadbeef);
392         res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, &pcReturned);
393         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
394             level, res, GetLastError(), pcbNeeded, pcReturned);
395         /* We can compare the returned Data with the Registry / "win.ini",[Ports] here */
396
397         pcbNeeded = 0xdeadbeef;
398         pcReturned = 0xdeadbeef;
399         SetLastError(0xdeadbeef);
400         res = pEnumPorts(NULL, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
401         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
402             level, res, GetLastError(), pcbNeeded, pcReturned);
403
404         pcbNeeded = 0xdeadbeef;
405         pcReturned = 0xdeadbeef;
406         SetLastError(0xdeadbeef);
407         res = pEnumPorts(NULL, level, buffer, cbBuf-1, &pcbNeeded, &pcReturned);
408         ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
409             "(%d) returned %d with %u and %d, %d (expected '0' with "
410             "ERROR_INSUFFICIENT_BUFFER)\n",
411             level, res, GetLastError(), pcbNeeded, pcReturned);
412
413         if (0)
414         {
415         /* The following tests crash this app with native localmon/localspl */
416         res = pEnumPorts(NULL, level, NULL, cbBuf, &pcbNeeded, &pcReturned);
417         res = pEnumPorts(NULL, level, buffer, cbBuf, NULL, &pcReturned);
418         res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, NULL);
419         }
420
421         /* The Servername is ignored */
422         pcbNeeded = 0xdeadbeef;
423         pcReturned = 0xdeadbeef;
424         SetLastError(0xdeadbeef);
425         res = pEnumPorts(emptyW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
426         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
427             level, res, GetLastError(), pcbNeeded, pcReturned);
428
429         pcbNeeded = 0xdeadbeef;
430         pcReturned = 0xdeadbeef;
431         SetLastError(0xdeadbeef);
432         res = pEnumPorts(server_does_not_existW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
433         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
434             level, res, GetLastError(), pcbNeeded, pcReturned);
435
436         HeapFree(GetProcessHeap(), 0, buffer);
437     }
438 }
439
440 /* ########################### */
441
442
443 static void test_InitializePrintMonitor(void)
444 {
445     LPMONITOREX res;
446
447     SetLastError(0xdeadbeef);
448     res = pInitializePrintMonitor(NULL);
449     /* The Parameter was unchecked before w2k */
450     ok( res || (GetLastError() == ERROR_INVALID_PARAMETER),
451         "returned %p with %u\n (expected '!= NULL' or: NULL with "
452         "ERROR_INVALID_PARAMETER)\n", res, GetLastError());
453
454     SetLastError(0xdeadbeef);
455     res = pInitializePrintMonitor(emptyW);
456     ok( res || (GetLastError() == ERROR_INVALID_PARAMETER),
457         "returned %p with %u\n (expected '!= NULL' or: NULL with "
458         "ERROR_INVALID_PARAMETER)\n", res, GetLastError());
459
460
461     /* Every call with a non-empty string returns the same Pointer */
462     SetLastError(0xdeadbeef);
463     res = pInitializePrintMonitor(Monitors_LocalPortW);
464     ok( res == pm,
465         "returned %p with %u (expected %p)\n", res, GetLastError(), pm);
466 }
467
468 /* ########################### */
469
470 static void test_XcvClosePort(void)
471 {
472     DWORD   res;
473     HANDLE hXcv2;
474
475
476     if (0)
477     {
478     /* crash with native localspl.dll (w2k+xp) */
479     res = pXcvClosePort(NULL);
480     res = pXcvClosePort(INVALID_HANDLE_VALUE);
481     }
482
483
484     SetLastError(0xdeadbeef);
485     hXcv2 = (HANDLE) 0xdeadbeef;
486     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2);
487     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
488
489     if (res) {
490         SetLastError(0xdeadbeef);
491         res = pXcvClosePort(hXcv2);
492         ok( res, "returned %d with %u (expected '!= 0')\n", res, GetLastError());
493
494         if (0)
495         {
496         /* test for "Double Free": crash with native localspl.dll (w2k+xp) */
497         res = pXcvClosePort(hXcv2);
498         }
499     }
500 }
501
502 /* ########################### */
503
504 static void test_XcvDataPort_AddPort(void)
505 {
506     DWORD   res;
507
508
509     /*
510      * The following tests crash with native localspl.dll on w2k and xp,
511      * but it works, when the native dll (w2k and xp) is used in wine.
512      * also tested (same crash): replacing emptyW with portname_lpt1W
513      * and replacing "NULL, 0, NULL" with "buffer, MAX_PATH, &needed"
514      *
515      * We need to use a different API (AddPortEx) instead
516      */
517     if (0)
518     {
519     /* create a Port for a normal, writable file */
520     SetLastError(0xdeadbeef);
521     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
522
523     /* add our testport again */
524     SetLastError(0xdeadbeef);
525     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
526
527     /* create a well-known Port  */
528     SetLastError(0xdeadbeef);
529     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL);
530
531     SetLastError(0xdeadbeef);
532     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL);
533     /* native localspl.dll on wine: ERROR_ALREADY_EXISTS */
534
535     /* ERROR_ALREADY_EXISTS is also returned from native localspl.dll on wine,
536        when "RPT1:" was already installed for redmonnt.dll:
537        res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_rpt1W, ...
538     */
539
540     /* cleanup */
541     SetLastError(0xdeadbeef);
542     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
543     }
544
545 }
546
547 /* ########################### */
548
549 static void test_XcvDataPort_ConfigureLPTPortCommandOK(void)
550 {
551     CHAR    org_value[16];
552     CHAR    buffer[16];
553     HKEY    hroot = NULL;
554     DWORD   res;
555     DWORD   needed;
556
557
558     /* Read the original value from the registry */
559     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot);
560     if (res == ERROR_ACCESS_DENIED) {
561         skip("ACCESS_DENIED\n");
562         return;
563     }
564
565     if (res != ERROR_SUCCESS) {
566         /* unable to open the registry: skip the test */
567         skip("got %d\n", res);
568         return;
569     }
570     org_value[0] = '\0';
571     needed = sizeof(org_value)-1 ;
572     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed);
573     ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND),
574         "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or "
575         "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value);
576
577     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
578
579     /* set to "0" */
580     needed = (DWORD) 0xdeadbeef;
581     SetLastError(0xdeadbeef);
582     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_0W, sizeof(num_0W), NULL, 0, &needed);
583     if (res == ERROR_INVALID_PARAMETER) {
584         skip("'ConfigureLPTPortCommandOK' not supported\n");
585         return;
586     }
587     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
588     needed = sizeof(buffer)-1 ;
589     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
590     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_0A) == 0),
591         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
592         res, buffer, num_0A);
593
594
595     /* set to "1" */
596     needed = (DWORD) 0xdeadbeef;
597     SetLastError(0xdeadbeef);
598     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1W, sizeof(num_1W), NULL, 0, &needed);
599     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
600     needed = sizeof(buffer)-1 ;
601     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
602     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1A) == 0),
603         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
604         res, buffer, num_1A);
605
606     /* set to "999999" */
607     needed = (DWORD) 0xdeadbeef;
608     SetLastError(0xdeadbeef);
609     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_999999W, sizeof(num_999999W), NULL, 0, &needed);
610     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
611     needed = sizeof(buffer)-1 ;
612     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
613     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_999999A) == 0),
614         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
615         res, buffer, num_999999A);
616
617     /* set to "1000000" */
618     needed = (DWORD) 0xdeadbeef;
619     SetLastError(0xdeadbeef);
620     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1000000W, sizeof(num_1000000W), NULL, 0, &needed);
621     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
622     needed = sizeof(buffer)-1 ;
623     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
624     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1000000A) == 0),
625         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
626         res, buffer, num_1000000A);
627
628     /*  using cmd_ConfigureLPTPortCommandOKW with does_not_existW:
629         the string "does_not_exist" is written to the registry */
630
631
632     /* restore the original value */
633     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
634     if (org_value[0]) {
635         res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1);
636         ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value);
637     }
638
639     RegCloseKey(hroot);
640
641 }
642
643 /* ########################### */
644
645 static void test_XcvDataPort_DeletePort(void)
646 {
647     DWORD   res;
648     DWORD   needed;
649
650
651     /* cleanup: just to make sure */
652     needed = (DWORD) 0xdeadbeef;
653     SetLastError(0xdeadbeef);
654     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
655     ok( !res  || (res == ERROR_FILE_NOT_FOUND),
656         "returned %d with %u (expected ERROR_SUCCESS or ERROR_FILE_NOT_FOUND)\n",
657         res, GetLastError());
658
659
660     /* ToDo: cmd_AddPortW for tempfileW, then cmd_DeletePortW for the existing Port */
661
662
663     /* try to delete a nonexistent Port */
664     needed = (DWORD) 0xdeadbeef;
665     SetLastError(0xdeadbeef);
666     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
667     ok( res == ERROR_FILE_NOT_FOUND,
668         "returned %d with %u (expected ERROR_FILE_NOT_FOUND)\n", res, GetLastError());
669
670     /* emptyW as Portname: ERROR_FILE_NOT_FOUND is returned */
671     /* NULL as Portname: Native localspl.dll crashed */
672
673 }
674
675 /* ########################### */
676
677 static void test_XcvDataPort_GetTransmissionRetryTimeout(void)
678 {
679     CHAR    org_value[16];
680     HKEY    hroot = NULL;
681     DWORD   buffer[2];
682     DWORD   res;
683     DWORD   needed;
684     DWORD   len;
685
686
687     /* ask for needed size */
688     needed = (DWORD) 0xdeadbeef;
689     SetLastError(0xdeadbeef);
690     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, NULL, 0, &needed);
691     if (res == ERROR_INVALID_PARAMETER) {
692         skip("'GetTransmissionRetryTimeout' not supported\n");
693         return;
694     }
695     len = sizeof(DWORD);
696     ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed == len),
697         "returned %d with %u and %u (expected ERROR_INSUFFICIENT_BUFFER "
698         "and '%u')\n", res, GetLastError(), needed, len);
699     len = needed;
700
701     /* Read the original value from the registry */
702     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot);
703     if (res == ERROR_ACCESS_DENIED) {
704         skip("ACCESS_DENIED\n");
705         return;
706     }
707
708     if (res != ERROR_SUCCESS) {
709         /* unable to open the registry: skip the test */
710         skip("got %d\n", res);
711         return;
712     }
713
714     org_value[0] = '\0';
715     needed = sizeof(org_value)-1 ;
716     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed);
717     ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND),
718         "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or "
719         "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value);
720
721     /* Get default value (documented as 90 in the w2k reskit, but that is wrong) */
722     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
723     needed = (DWORD) 0xdeadbeef;
724     buffer[0] = 0xdeadbeef;
725     SetLastError(0xdeadbeef);
726     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
727     ok( (res == ERROR_SUCCESS) && (buffer[0] == 45),
728         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
729         "for '45')\n", res, GetLastError(), needed, buffer[0]);
730
731     /* the default timeout is returned, when the value is empty */
732     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)emptyA, 1);
733     needed = (DWORD) 0xdeadbeef;
734     buffer[0] = 0xdeadbeef;
735     SetLastError(0xdeadbeef);
736     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
737     ok( (res == ERROR_SUCCESS) && (buffer[0] == 45),
738         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
739         "for '45')\n", res, GetLastError(), needed, buffer[0]);
740
741     /* the dialog is limited (1 - 999999), but that is done somewhere else */
742     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_0A, lstrlenA(num_0A)+1);
743     needed = (DWORD) 0xdeadbeef;
744     buffer[0] = 0xdeadbeef;
745     SetLastError(0xdeadbeef);
746     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
747     ok( (res == ERROR_SUCCESS) && (buffer[0] == 0),
748         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
749         "for '0')\n", res, GetLastError(), needed, buffer[0]);
750
751
752     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1A, lstrlenA(num_1A)+1);
753     needed = (DWORD) 0xdeadbeef;
754     buffer[0] = 0xdeadbeef;
755     SetLastError(0xdeadbeef);
756     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
757     ok( (res == ERROR_SUCCESS) && (buffer[0] == 1),
758         "returned %d with %u and %u for %d\n (expected 'ERROR_SUCCESS' "
759         "for '1')\n", res, GetLastError(), needed, buffer[0]);
760
761     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_999999A, lstrlenA(num_999999A)+1);
762     needed = (DWORD) 0xdeadbeef;
763     buffer[0] = 0xdeadbeef;
764     SetLastError(0xdeadbeef);
765     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
766     ok( (res == ERROR_SUCCESS) && (buffer[0] == 999999),
767         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
768         "for '999999')\n", res, GetLastError(), needed, buffer[0]);
769
770
771     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1000000A, lstrlenA(num_1000000A)+1);
772     needed = (DWORD) 0xdeadbeef;
773     buffer[0] = 0xdeadbeef;
774     SetLastError(0xdeadbeef);
775     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
776     ok( (res == ERROR_SUCCESS) && (buffer[0] == 1000000),
777         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
778         "for '1000000')\n", res, GetLastError(), needed, buffer[0]);
779
780     /* restore the original value */
781     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
782     if (org_value[0]) {
783         res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1);
784         ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value);
785     }
786
787     RegCloseKey(hroot);
788 }
789
790 /* ########################### */
791
792 static void test_XcvDataPort_MonitorUI(void)
793 {
794     DWORD   res;
795     BYTE    buffer[MAX_PATH + 2];
796     DWORD   needed;
797     DWORD   len;
798
799
800     /* ask for needed size */
801     needed = (DWORD) 0xdeadbeef;
802     SetLastError(0xdeadbeef);
803     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, 0, &needed);
804     if (res == ERROR_INVALID_PARAMETER) {
805         skip("'MonitorUI' nor supported\n");
806         return;
807     }
808     ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed <= MAX_PATH),
809         "returned %d with %u and 0x%x (expected 'ERROR_INSUFFICIENT_BUFFER' "
810         " and '<= MAX_PATH')\n", res, GetLastError(), needed);
811
812     if (needed > MAX_PATH) {
813         skip("buffer overflow (%u)\n", needed);
814         return;
815     }
816     len = needed;
817
818     /* the command is required */
819     needed = (DWORD) 0xdeadbeef;
820     SetLastError(0xdeadbeef);
821     res = pXcvDataPort(hXcv, emptyW, NULL, 0, NULL, 0, &needed);
822     ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x "
823         "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed);
824
825     if (0) {
826     /* crash with native localspl.dll (w2k+xp) */
827     res = pXcvDataPort(hXcv, NULL, NULL, 0, buffer, MAX_PATH, &needed);
828     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, len, &needed);
829     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, NULL);
830     }
831
832
833     /* hXcv is ignored for the command "MonitorUI" */
834     needed = (DWORD) 0xdeadbeef;
835     SetLastError(0xdeadbeef);
836     res = pXcvDataPort(NULL, cmd_MonitorUIW, NULL, 0, buffer, len, &needed);
837     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
838         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
839
840
841     /* pszDataName is case-sensitive */
842     memset(buffer, 0, len);
843     needed = (DWORD) 0xdeadbeef;
844     SetLastError(0xdeadbeef);
845     res = pXcvDataPort(hXcv, cmd_MonitorUI_lcaseW, NULL, 0, buffer, len, &needed);
846     ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x "
847         "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed);
848
849     /* off by one: larger  */
850     needed = (DWORD) 0xdeadbeef;
851     SetLastError(0xdeadbeef);
852     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len+1, &needed);
853     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
854         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
855
856
857     /* off by one: smaller */
858     /* the buffer is not modified for NT4, w2k, XP */
859     needed = (DWORD) 0xdeadbeef;
860     SetLastError(0xdeadbeef);
861     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len-1, &needed);
862     ok( res == ERROR_INSUFFICIENT_BUFFER, "returned %d with %u and 0x%x "
863         "(expected 'ERROR_INSUFFICIENT_BUFFER')\n", res, GetLastError(), needed);
864
865     /* Normal use. The DLL-Name without a Path is returned */
866     memset(buffer, 0, len);
867     needed = (DWORD) 0xdeadbeef;
868     SetLastError(0xdeadbeef);
869     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, &needed);
870     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
871         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
872
873
874     /* small check without access-rights: */
875     if (!hXcv_noaccess) return;
876
877     /* The ACCESS_MASK is ignored for "MonitorUI" */
878     memset(buffer, 0, len);
879     needed = (DWORD) 0xdeadbeef;
880     SetLastError(0xdeadbeef);
881     res = pXcvDataPort(hXcv_noaccess, cmd_MonitorUIW, NULL, 0, buffer, sizeof(buffer), &needed);
882     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
883         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
884 }
885
886 /* ########################### */
887
888 static void test_XcvDataPort_PortIsValid(void)
889 {
890     DWORD   res;
891     DWORD   needed;
892
893     /* normal use: "LPT1:" */
894     needed = (DWORD) 0xdeadbeef;
895     SetLastError(0xdeadbeef);
896     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed);
897     if (res == ERROR_INVALID_PARAMETER) {
898         skip("'PostIsValid' not supported\n");
899         return;
900     }
901     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
902
903
904     if (0) {
905     /* crash with native localspl.dll (w2k+xp) */
906     res = pXcvDataPort(hXcv, cmd_PortIsValidW, NULL, 0, NULL, 0, &needed);
907     }
908
909
910     /* hXcv is ignored for the command "PortIsValid" */
911     needed = (DWORD) 0xdeadbeef;
912     SetLastError(0xdeadbeef);
913     res = pXcvDataPort(NULL, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL);
914     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
915
916     /* needed is ignored */
917     needed = (DWORD) 0xdeadbeef;
918     SetLastError(0xdeadbeef);
919     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL);
920     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
921
922
923     /* cbInputData is ignored */
924     needed = (DWORD) 0xdeadbeef;
925     SetLastError(0xdeadbeef);
926     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 0, NULL, 0, &needed);
927     ok( res == ERROR_SUCCESS,
928         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
929         res, GetLastError(), needed);
930
931     needed = (DWORD) 0xdeadbeef;
932     SetLastError(0xdeadbeef);
933     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 1, NULL, 0, &needed);
934     ok( res == ERROR_SUCCESS,
935         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
936         res, GetLastError(), needed);
937
938     needed = (DWORD) 0xdeadbeef;
939     SetLastError(0xdeadbeef);
940     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -1, NULL, 0, &needed);
941     ok( res == ERROR_SUCCESS,
942         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
943         res, GetLastError(), needed);
944
945     needed = (DWORD) 0xdeadbeef;
946     SetLastError(0xdeadbeef);
947     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -2, NULL, 0, &needed);
948     ok( res == ERROR_SUCCESS,
949         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
950         res, GetLastError(), needed);
951
952
953     /* an empty name is not allowed */
954     needed = (DWORD) 0xdeadbeef;
955     SetLastError(0xdeadbeef);
956     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) emptyW, sizeof(emptyW), NULL, 0, &needed);
957     ok( res == ERROR_PATH_NOT_FOUND,
958         "returned %d with %u and 0x%x (expected ERROR_PATH_NOT_FOUND)\n",
959         res, GetLastError(), needed);
960
961
962     /* a directory is not allowed */
963     needed = (DWORD) 0xdeadbeef;
964     SetLastError(0xdeadbeef);
965     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempdirW, (lstrlenW(tempdirW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
966     /* XP(admin): ERROR_INVALID_NAME, XP(user): ERROR_PATH_NOT_FOUND, w2k ERROR_ACCESS_DENIED */
967     ok( (res == ERROR_INVALID_NAME) || (res == ERROR_PATH_NOT_FOUND) ||
968         (res == ERROR_ACCESS_DENIED), "returned %d with %u and 0x%x "
969         "(expected ERROR_INVALID_NAME, ERROR_PATH_NOT_FOUND or ERROR_ACCESS_DENIED)\n",
970         res, GetLastError(), needed);
971
972
973     /* test more valid well known Ports: */
974     needed = (DWORD) 0xdeadbeef;
975     SetLastError(0xdeadbeef);
976     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt2W, sizeof(portname_lpt2W), NULL, 0, &needed);
977     ok( res == ERROR_SUCCESS,
978         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
979         res, GetLastError(), needed);
980
981
982     needed = (DWORD) 0xdeadbeef;
983     SetLastError(0xdeadbeef);
984     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com1W, sizeof(portname_com1W), NULL, 0, &needed);
985     ok( res == ERROR_SUCCESS,
986         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
987         res, GetLastError(), needed);
988
989
990     needed = (DWORD) 0xdeadbeef;
991     SetLastError(0xdeadbeef);
992     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com2W, sizeof(portname_com2W), NULL, 0, &needed);
993     ok( res == ERROR_SUCCESS,
994         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
995         res, GetLastError(), needed);
996
997
998     needed = (DWORD) 0xdeadbeef;
999     SetLastError(0xdeadbeef);
1000     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_fileW, sizeof(portname_fileW), NULL, 0, &needed);
1001     ok( res == ERROR_SUCCESS,
1002         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1003         res, GetLastError(), needed);
1004
1005
1006     /* a normal, writable file is allowed */
1007     needed = (DWORD) 0xdeadbeef;
1008     SetLastError(0xdeadbeef);
1009     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1010     ok( res == ERROR_SUCCESS,
1011         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1012         res, GetLastError(), needed);
1013
1014
1015     /* small check without access-rights: */
1016     if (!hXcv_noaccess) return;
1017
1018     /* The ACCESS_MASK from XcvOpenPort is ignored in "PortIsValid" */
1019     needed = (DWORD) 0xdeadbeef;
1020     SetLastError(0xdeadbeef);
1021     res = pXcvDataPort(hXcv_noaccess, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed);
1022     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1023
1024 }
1025
1026 /* ########################### */
1027
1028 static void test_XcvOpenPort(void)
1029 {
1030     DWORD   res;
1031     HANDLE  hXcv2;
1032
1033
1034     if (0)
1035     {
1036     /* crash with native localspl.dll (w2k+xp) */
1037     res = pXcvOpenPort(NULL, SERVER_ACCESS_ADMINISTER, &hXcv2);
1038     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, NULL);
1039     }
1040
1041
1042     /* The returned handle is the result from a previous "spoolss.dll,DllAllocSplMem" */
1043     SetLastError(0xdeadbeef);
1044     hXcv2 = (HANDLE) 0xdeadbeef;
1045     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2);
1046     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1047     if (res) pXcvClosePort(hXcv2);
1048
1049
1050     /* The ACCESS_MASK is not checked in XcvOpenPort */
1051     SetLastError(0xdeadbeef);
1052     hXcv2 = (HANDLE) 0xdeadbeef;
1053     res = pXcvOpenPort(emptyW, 0, &hXcv2);
1054     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1055     if (res) pXcvClosePort(hXcv2);
1056
1057
1058     /* A copy of pszObject is saved in the Memory-Block */
1059     SetLastError(0xdeadbeef);
1060     hXcv2 = (HANDLE) 0xdeadbeef;
1061     res = pXcvOpenPort(portname_lpt1W, SERVER_ALL_ACCESS, &hXcv2);
1062     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1063     if (res) pXcvClosePort(hXcv2);
1064
1065     SetLastError(0xdeadbeef);
1066     hXcv2 = (HANDLE) 0xdeadbeef;
1067     res = pXcvOpenPort(portname_fileW, SERVER_ALL_ACCESS, &hXcv2);
1068     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1069     if (res) pXcvClosePort(hXcv2);
1070
1071 }
1072
1073 /* ########################### */
1074
1075 #define GET_MONITOR_FUNC(name) \
1076             if(numentries > 0) { \
1077                 numentries--; \
1078                 p##name = (void *) pm->Monitor.pfn##name ;  \
1079             }
1080
1081
1082 START_TEST(localmon)
1083 {
1084     DWORD   numentries;
1085     DWORD   res;
1086
1087     /* This DLL does not exist on Win9x */
1088     hdll = LoadLibraryA("localspl.dll");
1089     if (!hdll) {
1090         skip("localspl.dll cannot be loaded, most likely running on Win9x\n");
1091         return;
1092     }
1093
1094     tempdirW[0] = '\0';
1095     tempfileW[0] = '\0';
1096     res = GetTempPathW(MAX_PATH, tempdirW);
1097     ok(res != 0, "with %u\n", GetLastError());
1098     res = GetTempFileNameW(tempdirW, wineW, 0, tempfileW);
1099     ok(res != 0, "with %u\n", GetLastError());
1100
1101     pInitializePrintMonitor = (void *) GetProcAddress(hdll, "InitializePrintMonitor");
1102
1103     if (!pInitializePrintMonitor) {
1104         /* The Monitor for "Local Ports" was in a separate dll before w2k */
1105         hlocalmon = LoadLibraryA("localmon.dll");
1106         if (hlocalmon) {
1107             pInitializePrintMonitor = (void *) GetProcAddress(hlocalmon, "InitializePrintMonitor");
1108         }
1109     }
1110     if (!pInitializePrintMonitor) return;
1111
1112     /* Native localmon.dll / localspl.dll need a valid Port-Entry in:
1113        a) since xp: HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports 
1114        b) up to w2k: Section "Ports" in win.ini
1115        or InitializePrintMonitor fails. */
1116     pm = pInitializePrintMonitor(Monitors_LocalPortW);
1117     if (pm) {
1118         numentries = (pm->dwMonitorSize ) / sizeof(VOID *);
1119         /* NT4: 14, since w2k: 17 */
1120         ok( numentries == 14 || numentries == 17, 
1121             "dwMonitorSize (%d) => %d Functions\n", pm->dwMonitorSize, numentries);
1122
1123         GET_MONITOR_FUNC(EnumPorts);
1124         GET_MONITOR_FUNC(OpenPort);
1125         GET_MONITOR_FUNC(OpenPortEx);
1126         GET_MONITOR_FUNC(StartDocPort);
1127         GET_MONITOR_FUNC(WritePort);
1128         GET_MONITOR_FUNC(ReadPort);
1129         GET_MONITOR_FUNC(EndDocPort);
1130         GET_MONITOR_FUNC(ClosePort);
1131         GET_MONITOR_FUNC(AddPort);
1132         GET_MONITOR_FUNC(AddPortEx);
1133         GET_MONITOR_FUNC(ConfigurePort);
1134         GET_MONITOR_FUNC(DeletePort);
1135         GET_MONITOR_FUNC(GetPrinterDataFromPort);
1136         GET_MONITOR_FUNC(SetPortTimeOuts);
1137         GET_MONITOR_FUNC(XcvOpenPort);
1138         GET_MONITOR_FUNC(XcvDataPort);
1139         GET_MONITOR_FUNC(XcvClosePort);
1140
1141         if ((pXcvOpenPort) && (pXcvDataPort) && (pXcvClosePort)) {
1142             SetLastError(0xdeadbeef);
1143             res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
1144             ok(res, "hXcv: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv);
1145
1146             SetLastError(0xdeadbeef);
1147             res = pXcvOpenPort(emptyW, 0, &hXcv_noaccess);
1148             ok(res, "hXcv_noaccess: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv_noaccess);
1149         }
1150     }
1151
1152     test_InitializePrintMonitor();
1153
1154     test_AddPort();
1155     test_AddPortEx();
1156     test_ConfigurePort();
1157     test_DeletePort();
1158     test_EnumPorts();
1159     if ( !hXcv ) {
1160         skip("Xcv not supported\n");
1161     }
1162     else
1163     {
1164         test_XcvClosePort();
1165         test_XcvDataPort_AddPort();
1166         test_XcvDataPort_ConfigureLPTPortCommandOK();
1167         test_XcvDataPort_DeletePort();
1168         test_XcvDataPort_GetTransmissionRetryTimeout();
1169         test_XcvDataPort_MonitorUI();
1170         test_XcvDataPort_PortIsValid();
1171         test_XcvOpenPort();
1172
1173         pXcvClosePort(hXcv);
1174     }
1175     if (hXcv_noaccess) pXcvClosePort(hXcv_noaccess);
1176
1177     /* Cleanup our temporary file */
1178     DeleteFileW(tempfileW);
1179 }