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