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