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