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