1 /*
2  * Unit test suite for localspl API functions: local print monitor
3  *
4  * Copyright 2006-2007 Detlef Riekenberg
5  * Copyright 2019 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  */
22 
23 #include <stdarg.h>
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 
31 #include "winspool.h"
32 #include "ddk/winsplp.h"
33 
34 #include "wine/test.h"
35 
36 
37 /* ##### */
38 
39 static HMODULE  hdll;
40 static HMODULE  hlocalmon;
41 static HANDLE   hmon;
42 static LPMONITOREX (WINAPI *pInitializePrintMonitor)(LPWSTR);
43 static LPMONITOR2  (WINAPI *pInitializePrintMonitor2)(PMONITORINIT, LPHANDLE);
44 
45 static LPMONITOREX pm;
46 static LPMONITOR2 pm2;
47 static BOOL  (WINAPI *pEnumPorts)(LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
48 static BOOL  (WINAPI *pEnumPorts2)(HANDLE, LPWSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD);
49 static BOOL  (WINAPI *pOpenPort)(LPWSTR, PHANDLE);
50 static BOOL  (WINAPI *pOpenPort2)(HANDLE, LPWSTR, PHANDLE);
51 static BOOL  (WINAPI *pOpenPortEx)(LPWSTR, LPWSTR, PHANDLE, struct _MONITOR *);
52 static BOOL  (WINAPI *pOpenPortEx2)(HANDLE, HANDLE, LPWSTR, LPWSTR, PHANDLE, struct _MONITOR2 *);
53 static BOOL  (WINAPI *pStartDocPort)(HANDLE, LPWSTR, DWORD, DWORD, LPBYTE);
54 static BOOL  (WINAPI *pWritePort)(HANDLE hPort, LPBYTE, DWORD, LPDWORD);
55 static BOOL  (WINAPI *pReadPort)(HANDLE hPort, LPBYTE, DWORD, LPDWORD);
56 static BOOL  (WINAPI *pEndDocPort)(HANDLE);
57 static BOOL  (WINAPI *pClosePort)(HANDLE);
58 static BOOL  (WINAPI *pAddPort)(LPWSTR, HWND, LPWSTR);
59 static BOOL  (WINAPI *pAddPort2)(HANDLE, LPWSTR, HWND, LPWSTR);
60 static BOOL  (WINAPI *pAddPortEx)(LPWSTR, DWORD, LPBYTE, LPWSTR);
61 static BOOL  (WINAPI *pAddPortEx2)(HANDLE, LPWSTR, DWORD, LPBYTE, LPWSTR);
62 static BOOL  (WINAPI *pConfigurePort)(LPWSTR, HWND, LPWSTR);
63 static BOOL  (WINAPI *pConfigurePort2)(HANDLE, LPWSTR, HWND, LPWSTR);
64 static BOOL  (WINAPI *pDeletePort)(LPWSTR, HWND, LPWSTR);
65 static BOOL  (WINAPI *pDeletePort2)(HANDLE, LPWSTR, HWND, LPWSTR);
66 static BOOL  (WINAPI *pGetPrinterDataFromPort)(HANDLE, DWORD, LPWSTR, LPWSTR, DWORD, LPWSTR, DWORD, LPDWORD);
67 static BOOL  (WINAPI *pSetPortTimeOuts)(HANDLE, LPCOMMTIMEOUTS, DWORD);
68 static BOOL  (WINAPI *pXcvOpenPort)(LPCWSTR, ACCESS_MASK, PHANDLE);
69 static BOOL  (WINAPI *pXcvOpenPort2)(HANDLE, LPCWSTR, ACCESS_MASK, PHANDLE);
70 static DWORD (WINAPI *pXcvDataPort)(HANDLE, LPCWSTR, PBYTE, DWORD, PBYTE, DWORD, PDWORD);
71 static BOOL  (WINAPI *pXcvClosePort)(HANDLE);
72 
73 static HANDLE hXcv;
74 static HANDLE hXcv_noaccess;
75 
76 /* ########################### */
77 
78 static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0};
79 static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e',
80                                     'L','P','T','P','o','r','t',
81                                     'C','o','m','m','a','n','d','O','K',0};
82 static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
83 static const WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t',
84                                     'T','r','a','n','s','m','i','s','s','i','o','n',
85                                     'R','e','t','r','y','T','i','m','e','o','u','t',0};
86 
87 static const WCHAR cmd_MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
88 static const WCHAR cmd_MonitorUI_lcaseW[] = {'m','o','n','i','t','o','r','u','i',0};
89 static const WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
90 static WCHAR does_not_existW[] = {'d','o','e','s','_','n','o','t','_','e','x','i','s','t',0};
91 static const CHAR emptyA[] = "";
92 static WCHAR emptyW[] = {0};
93 static WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
94 static WCHAR Monitors_LocalPortW[] = {
95                                 'S','y','s','t','e','m','\\',
96                                 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
97                                 'C','o','n','t','r','o','l','\\',
98                                 'P','r','i','n','t','\\',
99                                 'M','o','n','i','t','o','r','s','\\',
100                                 'L','o','c','a','l',' ','P','o','r','t',0};
101 
102 static const CHAR num_0A[] = "0";
103 static WCHAR num_0W[] = {'0',0};
104 static const CHAR num_1A[] = "1";
105 static WCHAR num_1W[] = {'1',0};
106 static const CHAR num_999999A[] = "999999";
107 static WCHAR num_999999W[] = {'9','9','9','9','9','9',0};
108 static const CHAR num_1000000A[] = "1000000";
109 static WCHAR num_1000000W[] = {'1','0','0','0','0','0','0',0};
110 
111 static const WCHAR portname_comW[]  = {'C','O','M',0};
112 static WCHAR portname_com1W[] = {'C','O','M','1',':',0};
113 static WCHAR portname_com2W[] = {'C','O','M','2',':',0};
114 static WCHAR portname_fileW[] = {'F','I','L','E',':',0};
115 static const WCHAR portname_lptW[]  = {'L','P','T',0};
116 static WCHAR portname_lpt1W[] = {'L','P','T','1',':',0};
117 static WCHAR portname_lpt2W[] = {'L','P','T','2',':',0};
118 static WCHAR server_does_not_existW[] = {'\\','\\','d','o','e','s','_','n','o','t','_','e','x','i','s','t',0};
119 
120 static const CHAR TransmissionRetryTimeoutA[] = {'T','r','a','n','s','m','i','s','s','i','o','n',
121                                     'R','e','t','r','y','T','i','m','e','o','u','t',0};
122 
123 static const CHAR WinNT_CV_WindowsA[] = {'S','o','f','t','w','a','r','e','\\',
124                                          'M','i','c','r','o','s','o','f','t','\\',
125                                          'W','i','n','d','o','w','s',' ','N','T','\\',
126                                          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
127                                          'W','i','n','d','o','w','s',0};
128 static WCHAR wineW[] = {'W','i','n','e',0};
129 
130 static WCHAR tempdirW[MAX_PATH];
131 static WCHAR tempfileW[MAX_PATH];
132 
133 #define PORTNAME_PREFIX  3
134 #define PORTNAME_MINSIZE 5
135 #define PORTNAME_MAXSIZE 10
136 static WCHAR have_com[PORTNAME_MAXSIZE];
137 static WCHAR have_lpt[PORTNAME_MAXSIZE];
138 static WCHAR have_file[PORTNAME_MAXSIZE];
139 
140 /* ########################### */
141 
CreateKey(HANDLE hcKey,LPCWSTR pszSubKey,DWORD dwOptions,REGSAM samDesired,PSECURITY_ATTRIBUTES pSecurityAttributes,PHANDLE phckResult,PDWORD pdwDisposition,HANDLE hSpooler)142 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions,
143                 REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes,
144                 PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
145 {
146     ok(0, "should not be called\n");
147     return ERROR_CALL_NOT_IMPLEMENTED;
148 }
149 
OpenKey(HANDLE hcKey,LPCWSTR pszSubKey,REGSAM samDesired,PHANDLE phkResult,HANDLE hSpooler)150 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired,
151                 PHANDLE phkResult, HANDLE hSpooler)
152 {
153     ok(0, "should not be called\n");
154     return ERROR_CALL_NOT_IMPLEMENTED;
155 }
156 
CloseKey(HANDLE hcKey,HANDLE hSpooler)157 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
158 {
159     ok(0, "should not be called\n");
160     return ERROR_CALL_NOT_IMPLEMENTED;
161 }
162 
DeleteKey(HANDLE hcKey,LPCWSTR pszSubKey,HANDLE hSpooler)163 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
164 {
165     ok(0, "should not be called\n");
166     return ERROR_CALL_NOT_IMPLEMENTED;
167 }
168 
EnumKey(HANDLE hcKey,DWORD dwIndex,LPWSTR pszName,PDWORD pcchName,PFILETIME pftLastWriteTime,HANDLE hSpooler)169 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName,
170                 PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
171 {
172     ok(0, "should not be called\n");
173     return ERROR_CALL_NOT_IMPLEMENTED;
174 }
175 
QueryInfoKey(HANDLE hcKey,PDWORD pcSubKeys,PDWORD pcbKey,PDWORD pcValues,PDWORD pcbValue,PDWORD pcbData,PDWORD pcbSecurityDescriptor,PFILETIME pftLastWriteTime,HANDLE hSpooler)176 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey,
177                 PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData,
178                 PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
179                 HANDLE hSpooler)
180 {
181     ok(0, "should not be called\n");
182     return ERROR_CALL_NOT_IMPLEMENTED;
183 }
184 
SetValue(HANDLE hcKey,LPCWSTR pszValue,DWORD dwType,const BYTE * pData,DWORD cbData,HANDLE hSpooler)185 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType,
186                 const BYTE* pData, DWORD cbData, HANDLE hSpooler)
187 {
188     ok(0, "should not be called\n");
189     return ERROR_CALL_NOT_IMPLEMENTED;
190 }
191 
DeleteValue(HANDLE hcKey,LPCWSTR pszValue,HANDLE hSpooler)192 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
193 {
194     ok(0, "should not be called\n");
195     return ERROR_CALL_NOT_IMPLEMENTED;
196 }
197 
EnumValue(HANDLE hcKey,DWORD dwIndex,LPWSTR pszValue,PDWORD pcbValue,PDWORD pType,PBYTE pData,PDWORD pcbData,HANDLE hSpooler)198 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue,
199                 PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData,
200                 HANDLE hSpooler)
201 {
202     ok(0, "should not be called\n");
203     return ERROR_CALL_NOT_IMPLEMENTED;
204 }
205 
QueryValue(HANDLE hcKey,LPCWSTR pszValue,PDWORD pType,PBYTE pData,PDWORD pcbData,HANDLE hSpooler)206 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType,
207                 PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
208 {
209     return ERROR_CALL_NOT_IMPLEMENTED;
210 }
211 
212 static MONITORREG monreg =
213 {
214     sizeof(MONITORREG),
215     CreateKey,
216     OpenKey,
217     CloseKey,
218     DeleteKey,
219     EnumKey,
220     QueryInfoKey,
221     SetValue,
222     DeleteValue,
223     EnumValue,
224     QueryValue
225 };
226 
delete_port(LPWSTR portname)227 static DWORD delete_port(LPWSTR portname)
228 {
229     DWORD   res;
230 
231     if (pDeletePort) {
232         res = pDeletePort(NULL, 0, portname);
233     }
234     else
235     {
236         res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) portname, (lstrlenW(portname) + 1) * sizeof(WCHAR), NULL, 0, NULL);
237     }
238     return res;
239 }
240 
241 /* ########################### */
242 
find_installed_ports(void)243 static void find_installed_ports(void)
244 {
245     PORT_INFO_1W * pi = NULL;
246     WCHAR   nameW[PORTNAME_MAXSIZE];
247     DWORD   needed;
248     DWORD   returned;
249     DWORD   res;
250     DWORD   id;
251 
252     have_com[0] = '\0';
253     have_lpt[0] = '\0';
254     have_file[0] = '\0';
255 
256     if (!pEnumPorts) return;
257 
258     res = pEnumPorts(NULL, 1, NULL, 0, &needed, &returned);
259     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
260         pi = HeapAlloc(GetProcessHeap(), 0, needed);
261     }
262     res = pEnumPorts(NULL, 1, (LPBYTE) pi, needed, &needed, &returned);
263 
264     if (!res) {
265         skip("no ports found\n");
266         HeapFree(GetProcessHeap(), 0, pi);
267         return;
268     }
269 
270     id = 0;
271     while (id < returned) {
272         res = lstrlenW(pi[id].pName);
273         if ((res >= PORTNAME_MINSIZE) && (res < PORTNAME_MAXSIZE) &&
274             (pi[id].pName[res-1] == ':')) {
275             /* copy only the prefix ("LPT" or "COM") */
276             memcpy(&nameW, pi[id].pName, PORTNAME_PREFIX * sizeof(WCHAR));
277             nameW[PORTNAME_PREFIX] = '\0';
278 
279             if (!have_com[0] && (lstrcmpiW(nameW, portname_comW) == 0)) {
280                 memcpy(&have_com, pi[id].pName, (res+1) * sizeof(WCHAR));
281             }
282 
283             if (!have_lpt[0] && (lstrcmpiW(nameW, portname_lptW) == 0)) {
284                 memcpy(&have_lpt, pi[id].pName, (res+1) * sizeof(WCHAR));
285             }
286 
287             if (!have_file[0] && (lstrcmpiW(pi[id].pName, portname_fileW) == 0)) {
288                 memcpy(&have_file, pi[id].pName, (res+1) * sizeof(WCHAR));
289             }
290         }
291         id++;
292     }
293 
294     HeapFree(GetProcessHeap(), 0, pi);
295 }
296 
297 /* ########################### */
298 
test_AddPort(void)299 static void test_AddPort(void)
300 {
301     DWORD   res;
302 
303     /* moved to localui.dll since w2k */
304     if (!pAddPort) return;
305 
306     if (0)
307     {
308         /* NT4 crash on this test */
309         pAddPort(NULL, 0, NULL);
310     }
311 
312     /*  Testing-Results (localmon.dll from NT4.0):
313         - The Servername is ignored
314         - Case of MonitorName is ignored
315     */
316 
317     SetLastError(0xdeadbeef);
318     res = pAddPort(NULL, 0, emptyW);
319     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
320 
321     SetLastError(0xdeadbeef);
322     res = pAddPort(NULL, 0, does_not_existW);
323     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
324 
325 }
326 
327 /* ########################### */
328 
test_AddPortEx(void)329 static void test_AddPortEx(void)
330 {
331     PORT_INFO_2W pi;
332     DWORD   res;
333 
334     if (!pAddPortEx) {
335         skip("AddPortEx\n");
336         return;
337     }
338     if ((!pDeletePort) &&  (!hXcv)) {
339         skip("No API to delete a Port\n");
340         return;
341     }
342 
343     /* start test with clean ports */
344     delete_port(tempfileW);
345 
346     pi.pPortName = tempfileW;
347     if (0) {
348         /* tests crash with native localspl.dll in w2k,
349            but works with native localspl.dll in wine */
350         SetLastError(0xdeadbeef);
351         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
352         trace("returned %u with %u\n", res, GetLastError() );
353         ok( res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
354 
355         /* port already exists: */
356         SetLastError(0xdeadbeef);
357         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
358         trace("returned %u with %u\n", res, GetLastError() );
359         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
360             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
361             res, GetLastError());
362         delete_port(tempfileW);
363 
364 
365         /*  NULL for pMonitorName is documented for Printmonitors, but
366             localspl.dll fails always with ERROR_INVALID_PARAMETER  */
367         SetLastError(0xdeadbeef);
368         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, NULL);
369         trace("returned %u with %u\n", res, GetLastError() );
370         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
371             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
372             res, GetLastError());
373         if (res) delete_port(tempfileW);
374 
375 
376         SetLastError(0xdeadbeef);
377         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, emptyW);
378         trace("returned %u with %u\n", res, GetLastError() );
379         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
380             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
381             res, GetLastError());
382         if (res) delete_port(tempfileW);
383 
384 
385         SetLastError(0xdeadbeef);
386         res = pAddPortEx(NULL, 1, (LPBYTE) &pi, does_not_existW);
387         trace("returned %u with %u\n", res, GetLastError() );
388         ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
389             "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
390             res, GetLastError());
391         if (res) delete_port(tempfileW);
392     }
393 
394     pi.pPortName = NULL;
395     SetLastError(0xdeadbeef);
396     res = pAddPortEx(NULL, 1, (LPBYTE) &pi, LocalPortW);
397     ok( !res && (GetLastError() == ERROR_INVALID_PARAMETER),
398         "got %u with %u (expected '0' with ERROR_INVALID_PARAMETER)\n",
399         res, GetLastError());
400 
401     /*  level 2 is documented as supported for Printmonitors,
402         but localspl.dll fails always with ERROR_INVALID_LEVEL */
403 
404     pi.pPortName = tempfileW;
405     pi.pMonitorName = LocalPortW;
406     pi.pDescription = wineW;
407     pi.fPortType = PORT_TYPE_WRITE;
408 
409     SetLastError(0xdeadbeef);
410     res = pAddPortEx(NULL, 2, (LPBYTE) &pi, LocalPortW);
411     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
412         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
413         res, GetLastError());
414     if (res) delete_port(tempfileW);
415 
416 
417     /* invalid levels */
418     SetLastError(0xdeadbeef);
419     res = pAddPortEx(NULL, 0, (LPBYTE) &pi, LocalPortW);
420     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
421         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
422         res, GetLastError());
423     if (res) delete_port(tempfileW);
424 
425 
426     SetLastError(0xdeadbeef);
427     res = pAddPortEx(NULL, 3, (LPBYTE) &pi, LocalPortW);
428     ok( !res && (GetLastError() == ERROR_INVALID_LEVEL),
429         "got %u with %u (expected '0' with ERROR_INVALID_LEVEL)\n",
430         res, GetLastError());
431     if (res) delete_port(tempfileW);
432 
433     /* cleanup */
434     delete_port(tempfileW);
435 }
436 
437 /* ########################### */
438 
test_ClosePort(void)439 static void test_ClosePort(void)
440 {
441     HANDLE  hPort;
442     HANDLE  hPort2;
443     LPWSTR  nameW = NULL;
444     DWORD   res;
445     DWORD   res2;
446 
447 
448     if (!pOpenPort || !pClosePort) return;
449 
450     if (have_com[0]) {
451         nameW = have_com;
452 
453         hPort = (HANDLE) 0xdeadbeef;
454         res = pOpenPort(nameW, &hPort);
455         hPort2 = (HANDLE) 0xdeadbeef;
456         res2 = pOpenPort(nameW, &hPort2);
457 
458         if (res2 && (hPort2 != hPort)) {
459             SetLastError(0xdeadbeef);
460             res2 = pClosePort(hPort2);
461             ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError());
462         }
463 
464         if (res) {
465             SetLastError(0xdeadbeef);
466             res = pClosePort(hPort);
467             ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
468         }
469     }
470 
471 
472     if (have_lpt[0]) {
473         nameW = have_lpt;
474 
475         hPort = (HANDLE) 0xdeadbeef;
476         res = pOpenPort(nameW, &hPort);
477         hPort2 = (HANDLE) 0xdeadbeef;
478         res2 = pOpenPort(nameW, &hPort2);
479 
480         if (res2 && (hPort2 != hPort)) {
481             SetLastError(0xdeadbeef);
482             res2 = pClosePort(hPort2);
483             ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError());
484         }
485 
486         if (res) {
487             SetLastError(0xdeadbeef);
488             res = pClosePort(hPort);
489             ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
490         }
491     }
492 
493 
494     if (have_file[0]) {
495         nameW = have_file;
496 
497         hPort = (HANDLE) 0xdeadbeef;
498         res = pOpenPort(nameW, &hPort);
499         hPort2 = (HANDLE) 0xdeadbeef;
500         res2 = pOpenPort(nameW, &hPort2);
501 
502         if (res2 && (hPort2 != hPort)) {
503             SetLastError(0xdeadbeef);
504             res2 = pClosePort(hPort2);
505             ok(res2, "got %u with %u (expected '!= 0')\n", res2, GetLastError());
506         }
507 
508         if (res) {
509             SetLastError(0xdeadbeef);
510             res = pClosePort(hPort);
511             ok(res, "got %u with %u (expected '!= 0')\n", res, GetLastError());
512         }
513 
514     }
515 
516     if (0) {
517         /* an invalid HANDLE crash native localspl.dll */
518 
519         SetLastError(0xdeadbeef);
520         res = pClosePort(NULL);
521         trace("got %u with %u\n", res, GetLastError());
522 
523         SetLastError(0xdeadbeef);
524         res = pClosePort( (HANDLE) 0xdeadbeef);
525         trace("got %u with %u\n", res, GetLastError());
526 
527         SetLastError(0xdeadbeef);
528         res = pClosePort(INVALID_HANDLE_VALUE);
529         trace("got %u with %u\n", res, GetLastError());
530     }
531 
532 }
533 
534 /* ########################### */
535 
test_ConfigurePort(void)536 static void test_ConfigurePort(void)
537 {
538     DWORD   res;
539 
540     /* moved to localui.dll since w2k */
541     if (!pConfigurePort) return;
542 
543     if (0)
544     {
545         /* NT4 crash on this test */
546         pConfigurePort(NULL, 0, NULL);
547     }
548 
549     /*  Testing-Results (localmon.dll from NT4.0):
550         - Case of Portname is ignored
551         - "COM1:" and "COM01:" are the same (Compared by value)
552         - Portname without ":" => Dialog "Nothing to configure" comes up; Success
553         - "LPT1:", "LPT0:" and "LPT:" are the same (Numbers in "LPT:" are ignored)
554         - Empty Servername (LPT1:) => Dialog comes up (Servername is ignored)
555         - "FILE:" => Dialog "Nothing to configure" comes up; Success
556         - Empty Portname =>  => Dialog "Nothing to configure" comes up; Success
557         - Port "does_not_exist" => Dialog "Nothing to configure" comes up; Success
558     */
559     if (winetest_interactive > 0) {
560 
561         SetLastError(0xdeadbeef);
562         res = pConfigurePort(NULL, 0, portname_com1W);
563         trace("returned %d with %u\n", res, GetLastError());
564 
565         SetLastError(0xdeadbeef);
566         res = pConfigurePort(NULL, 0, portname_lpt1W);
567         trace("returned %d with %u\n", res, GetLastError());
568 
569         SetLastError(0xdeadbeef);
570         res = pConfigurePort(NULL, 0, portname_fileW);
571         trace("returned %d with %u\n", res, GetLastError());
572     }
573 }
574 
575 /* ########################### */
576 
test_DeletePort(void)577 static void test_DeletePort(void)
578 {
579     DWORD   res;
580 
581     /* moved to localui.dll since w2k */
582     if (!pDeletePort) return;
583 
584     if (0)
585     {
586         /* NT4 crash on this test */
587         pDeletePort(NULL, 0, NULL);
588     }
589 
590     /*  Testing-Results (localmon.dll from NT4.0):
591         - Case of Portname is ignored (returned '1' on Success)
592         - "COM1:" and "COM01:" are different (Compared as string)
593         - server_does_not_exist (LPT1:) => Port deleted, Success (Servername is ignored)
594         - Empty Portname =>  => FALSE (LastError not changed)
595         - Port "does_not_exist" => FALSE (LastError not changed)
596     */
597 
598     SetLastError(0xdeadbeef);
599     res = pDeletePort(NULL, 0, emptyW);
600     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
601 
602     SetLastError(0xdeadbeef);
603     res = pDeletePort(NULL, 0, does_not_existW);
604     ok(!res, "returned %d with %u (expected '0')\n", res, GetLastError());
605 
606 }
607 
608 /* ########################### */
609 
test_EnumPorts(void)610 static void test_EnumPorts(void)
611 {
612     DWORD   res;
613     DWORD   level;
614     LPBYTE  buffer;
615     DWORD   cbBuf;
616     DWORD   pcbNeeded;
617     DWORD   pcReturned;
618 
619     if (!pEnumPorts) return;
620 
621     /* valid levels are 1 and 2 */
622     for(level = 0; level < 4; level++) {
623 
624         cbBuf = 0xdeadbeef;
625         pcReturned = 0xdeadbeef;
626         SetLastError(0xdeadbeef);
627         res = pEnumPorts(NULL, level, NULL, 0, &cbBuf, &pcReturned);
628 
629         /* use only a short test, when we test with an invalid level */
630         if(!level || (level > 2)) {
631             /* NT4 fails with ERROR_INVALID_LEVEL (as expected)
632                XP succeeds with ERROR_SUCCESS () */
633             ok( (cbBuf == 0) && (pcReturned == 0),
634                 "(%d) returned %d with %u and %d, %d (expected 0, 0)\n",
635                 level, res, GetLastError(), cbBuf, pcReturned);
636             continue;
637         }
638 
639         ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
640             "(%d) returned %d with %u and %d, %d (expected '0' with "
641             "ERROR_INSUFFICIENT_BUFFER)\n",
642             level, res, GetLastError(), cbBuf, pcReturned);
643 
644         buffer = HeapAlloc(GetProcessHeap(), 0, cbBuf * 2);
645         if (buffer == NULL) continue;
646 
647         pcbNeeded = 0xdeadbeef;
648         pcReturned = 0xdeadbeef;
649         SetLastError(0xdeadbeef);
650         res = pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, &pcReturned);
651         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
652             level, res, GetLastError(), pcbNeeded, pcReturned);
653         /* We can compare the returned Data with the Registry / "win.ini",[Ports] here */
654 
655         pcbNeeded = 0xdeadbeef;
656         pcReturned = 0xdeadbeef;
657         SetLastError(0xdeadbeef);
658         res = pEnumPorts(NULL, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
659         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
660             level, res, GetLastError(), pcbNeeded, pcReturned);
661 
662         pcbNeeded = 0xdeadbeef;
663         pcReturned = 0xdeadbeef;
664         SetLastError(0xdeadbeef);
665         res = pEnumPorts(NULL, level, buffer, cbBuf-1, &pcbNeeded, &pcReturned);
666         ok( !res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
667             "(%d) returned %d with %u and %d, %d (expected '0' with "
668             "ERROR_INSUFFICIENT_BUFFER)\n",
669             level, res, GetLastError(), pcbNeeded, pcReturned);
670 
671         if (0)
672         {
673             /* The following tests crash this app with native localmon/localspl */
674             pEnumPorts(NULL, level, NULL, cbBuf, &pcbNeeded, &pcReturned);
675             pEnumPorts(NULL, level, buffer, cbBuf, NULL, &pcReturned);
676             pEnumPorts(NULL, level, buffer, cbBuf, &pcbNeeded, NULL);
677         }
678 
679         /* The Servername is ignored */
680         pcbNeeded = 0xdeadbeef;
681         pcReturned = 0xdeadbeef;
682         SetLastError(0xdeadbeef);
683         res = pEnumPorts(emptyW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
684         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
685             level, res, GetLastError(), pcbNeeded, pcReturned);
686 
687         pcbNeeded = 0xdeadbeef;
688         pcReturned = 0xdeadbeef;
689         SetLastError(0xdeadbeef);
690         res = pEnumPorts(server_does_not_existW, level, buffer, cbBuf+1, &pcbNeeded, &pcReturned);
691         ok( res, "(%d) returned %d with %u and %d, %d (expected '!= 0')\n",
692             level, res, GetLastError(), pcbNeeded, pcReturned);
693 
694         HeapFree(GetProcessHeap(), 0, buffer);
695     }
696 }
697 
698 /* ########################### */
699 
700 
test_InitializePrintMonitor(void)701 static void test_InitializePrintMonitor(void)
702 {
703     LPMONITOREX res;
704 
705     if (!pInitializePrintMonitor) return;
706 
707     SetLastError(0xdeadbeef);
708     res = pInitializePrintMonitor(NULL);
709     /* The Parameter was unchecked before w2k */
710     ok( res || (GetLastError() == ERROR_INVALID_PARAMETER),
711         "returned %p with %u\n (expected '!= NULL' or: NULL with "
712         "ERROR_INVALID_PARAMETER)\n", res, GetLastError());
713 
714     SetLastError(0xdeadbeef);
715     res = pInitializePrintMonitor(emptyW);
716     ok( res || (GetLastError() == ERROR_INVALID_PARAMETER),
717         "returned %p with %u\n (expected '!= NULL' or: NULL with "
718         "ERROR_INVALID_PARAMETER)\n", res, GetLastError());
719 
720     /* Every call with a non-empty string returns the same Pointer */
721     SetLastError(0xdeadbeef);
722     res = pInitializePrintMonitor(Monitors_LocalPortW);
723     ok( res == pm,
724         "returned %p with %u (expected %p)\n", res, GetLastError(), pm);
725     ok(res->dwMonitorSize == sizeof(MONITOR), "wrong dwMonitorSize %u\n", res->dwMonitorSize);
726 }
727 
test_InitializePrintMonitor2(void)728 static void test_InitializePrintMonitor2(void)
729 {
730     MONITORINIT init;
731     MONITOR2 *monitor2;
732     HANDLE hmon;
733 
734     if (!pInitializePrintMonitor2) return;
735 
736     memset(&init, 0, sizeof(init));
737     init.cbSize = sizeof(init);
738     init.hckRegistryRoot = 0;
739     init.pMonitorReg = &monreg;
740     init.bLocal = TRUE;
741 
742     monitor2 = pInitializePrintMonitor2(&init, &hmon);
743     ok(monitor2 != NULL, "InitializePrintMonitor2 error %u\n", GetLastError());
744     ok(monitor2->cbSize >= FIELD_OFFSET(MONITOR2, pfnSendRecvBidiDataFromPort), "wrong cbSize %u\n", monitor2->cbSize);
745 }
746 
747 /* ########################### */
748 
test_OpenPort(void)749 static void test_OpenPort(void)
750 {
751     HANDLE  hPort;
752     HANDLE  hPort2;
753     LPWSTR  nameW = NULL;
754     DWORD   res;
755     DWORD   res2;
756 
757     if (!pOpenPort || !pClosePort) return;
758 
759     if (have_com[0]) {
760         nameW = have_com;
761 
762         hPort = (HANDLE) 0xdeadbeef;
763         SetLastError(0xdeadbeef);
764         res = pOpenPort(nameW, &hPort);
765         ok( res, "got %u with %u and %p (expected '!= 0')\n",
766             res, GetLastError(), hPort);
767 
768         /* the same HANDLE is returned for a second OpenPort in native localspl */
769         hPort2 = (HANDLE) 0xdeadbeef;
770         SetLastError(0xdeadbeef);
771         res2 = pOpenPort(nameW, &hPort2);
772         ok( res2, "got %u with %u and %p (expected '!= 0')\n",
773             res2, GetLastError(), hPort2);
774 
775         if (res) pClosePort(hPort);
776         if (res2 && (hPort2 != hPort)) pClosePort(hPort2);
777     }
778 
779     if (have_lpt[0]) {
780         nameW = have_lpt;
781 
782         hPort = (HANDLE) 0xdeadbeef;
783         SetLastError(0xdeadbeef);
784         res = pOpenPort(nameW, &hPort);
785         ok( res || (GetLastError() == ERROR_ACCESS_DENIED),
786             "got %u with %u and %p (expected '!= 0' or '0' with ERROR_ACCESS_DENIED)\n",
787             res, GetLastError(), hPort);
788 
789         /* the same HANDLE is returned for a second OpenPort in native localspl */
790         hPort2 = (HANDLE) 0xdeadbeef;
791         SetLastError(0xdeadbeef);
792         res2 = pOpenPort(nameW, &hPort2);
793         ok( res2 || (GetLastError() == ERROR_ACCESS_DENIED),
794             "got %u with %u and %p (expected '!= 0' or '0' with ERROR_ACCESS_DENIED)\n",
795             res2, GetLastError(), hPort2);
796 
797         if (res) pClosePort(hPort);
798         if (res2 && (hPort2 != hPort)) pClosePort(hPort2);
799     }
800 
801     if (have_file[0]) {
802         nameW = have_file;
803 
804         hPort = (HANDLE) 0xdeadbeef;
805         SetLastError(0xdeadbeef);
806         res = pOpenPort(nameW, &hPort);
807         ok( res, "got %u with %u and %p (expected '!= 0')\n",
808             res, GetLastError(), hPort);
809 
810         /* a different HANDLE is returned for a second OpenPort */
811         hPort2 = (HANDLE) 0xdeadbeef;
812         SetLastError(0xdeadbeef);
813         res2 = pOpenPort(nameW, &hPort2);
814         ok( res2 && (hPort2 != hPort),
815             "got %u with %u and %p (expected '!= 0' and '!= %p')\n",
816             res2, GetLastError(), hPort2, hPort);
817 
818         if (res) pClosePort(hPort);
819         if (res2 && (hPort2 != hPort)) pClosePort(hPort2);
820     }
821 
822     if (0) {
823         /* this test crash native localspl (w2k+xp) */
824         if (nameW) {
825             hPort = (HANDLE) 0xdeadbeef;
826             SetLastError(0xdeadbeef);
827             res = pOpenPort(nameW, NULL);
828             trace("got %u with %u and %p\n", res, GetLastError(), hPort);
829         }
830     }
831 
832     hPort = (HANDLE) 0xdeadbeef;
833     SetLastError(0xdeadbeef);
834     res = pOpenPort(does_not_existW, &hPort);
835     ok (!res && (hPort == (HANDLE) 0xdeadbeef),
836         "got %u with 0x%x and %p (expected '0' and 0xdeadbeef)\n", res, GetLastError(), hPort);
837     if (res) pClosePort(hPort);
838 
839     hPort = (HANDLE) 0xdeadbeef;
840     SetLastError(0xdeadbeef);
841     res = pOpenPort(emptyW, &hPort);
842     ok (!res && (hPort == (HANDLE) 0xdeadbeef),
843         "got %u with 0x%x and %p (expected '0' and 0xdeadbeef)\n", res, GetLastError(), hPort);
844     if (res) pClosePort(hPort);
845 
846 
847     /* NULL as name crash native localspl (w2k+xp) */
848     if (0) {
849         hPort = (HANDLE) 0xdeadbeef;
850         SetLastError(0xdeadbeef);
851         res = pOpenPort(NULL, &hPort);
852         trace("got %u with %u and %p\n", res, GetLastError(), hPort);
853     }
854 
855 }
856 
857 /* ########################### */
858 
test_XcvClosePort(void)859 static void test_XcvClosePort(void)
860 {
861     DWORD   res;
862     HANDLE hXcv2;
863 
864 
865     if (0)
866     {
867         /* crash with native localspl.dll (w2k+xp) */
868         pXcvClosePort(NULL);
869         pXcvClosePort(INVALID_HANDLE_VALUE);
870     }
871 
872 
873     SetLastError(0xdeadbeef);
874     hXcv2 = (HANDLE) 0xdeadbeef;
875     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2);
876     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
877 
878     if (res) {
879         SetLastError(0xdeadbeef);
880         res = pXcvClosePort(hXcv2);
881         ok(res, "returned %d with %u (expected '!= 0')\n", res, GetLastError());
882 
883         if (0)
884         {
885             /* test for "Double Free": crash with native localspl.dll (w2k+xp) */
886             pXcvClosePort(hXcv2);
887         }
888     }
889 }
890 
891 /* ########################### */
892 
test_XcvDataPort_AddPort(void)893 static void test_XcvDataPort_AddPort(void)
894 {
895     DWORD   res;
896 
897     /*
898      * The following tests crash with native localspl.dll on w2k and xp,
899      * but it works, when the native dll (w2k and xp) is used in wine.
900      * also tested (same crash): replacing emptyW with portname_lpt1W
901      * and replacing "NULL, 0, NULL" with "buffer, MAX_PATH, &needed"
902      *
903      * We need to use a different API (AddPortEx) instead
904      */
905     if (0)
906     {
907     /* create a Port for a normal, writable file */
908     SetLastError(0xdeadbeef);
909     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
910     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
911 
912     /* add our testport again */
913     SetLastError(0xdeadbeef);
914     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
915     ok( res == ERROR_ALREADY_EXISTS, "returned %d with %u (expected ERROR_ALREADY_EXISTS)\n", res, GetLastError());
916 
917     /* create a well-known Port  */
918     SetLastError(0xdeadbeef);
919     res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_lpt1W, (lstrlenW(portname_lpt1W) + 1) * sizeof(WCHAR), NULL, 0, NULL);
920     ok( res == ERROR_ALREADY_EXISTS, "returned %d with %u (expected ERROR_ALREADY_EXISTS)\n", res, GetLastError());
921 
922     /* ERROR_ALREADY_EXISTS is also returned from native localspl.dll on wine,
923        when "RPT1:" was already installed for redmonnt.dll:
924        res = pXcvDataPort(hXcv, cmd_AddPortW, (PBYTE) portname_rpt1W, ...
925     */
926 
927     /* cleanup */
928     SetLastError(0xdeadbeef);
929     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, NULL);
930     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
931     }
932 
933 }
934 
935 /* ########################### */
936 
test_XcvDataPort_ConfigureLPTPortCommandOK(void)937 static void test_XcvDataPort_ConfigureLPTPortCommandOK(void)
938 {
939     CHAR    org_value[16];
940     CHAR    buffer[16];
941     HKEY    hroot = NULL;
942     DWORD   res;
943     DWORD   needed;
944 
945 
946     /* Read the original value from the registry */
947     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot);
948     if (res == ERROR_ACCESS_DENIED) {
949         skip("ACCESS_DENIED\n");
950         return;
951     }
952 
953     if (res != ERROR_SUCCESS) {
954         /* unable to open the registry: skip the test */
955         skip("got %d\n", res);
956         return;
957     }
958     org_value[0] = '\0';
959     needed = sizeof(org_value)-1 ;
960     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed);
961     ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND),
962         "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or "
963         "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value);
964 
965     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
966 
967     /* set to "0" */
968     needed = (DWORD) 0xdeadbeef;
969     SetLastError(0xdeadbeef);
970     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_0W, sizeof(num_0W), NULL, 0, &needed);
971     if (res == ERROR_INVALID_PARAMETER) {
972         skip("'ConfigureLPTPortCommandOK' not supported\n");
973         return;
974     }
975     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
976     needed = sizeof(buffer)-1 ;
977     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
978     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_0A) == 0),
979         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
980         res, buffer, num_0A);
981 
982 
983     /* set to "1" */
984     needed = (DWORD) 0xdeadbeef;
985     SetLastError(0xdeadbeef);
986     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1W, sizeof(num_1W), NULL, 0, &needed);
987     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
988     needed = sizeof(buffer)-1 ;
989     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
990     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1A) == 0),
991         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
992         res, buffer, num_1A);
993 
994     /* set to "999999" */
995     needed = (DWORD) 0xdeadbeef;
996     SetLastError(0xdeadbeef);
997     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_999999W, sizeof(num_999999W), NULL, 0, &needed);
998     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
999     needed = sizeof(buffer)-1 ;
1000     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
1001     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_999999A) == 0),
1002         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
1003         res, buffer, num_999999A);
1004 
1005     /* set to "1000000" */
1006     needed = (DWORD) 0xdeadbeef;
1007     SetLastError(0xdeadbeef);
1008     res = pXcvDataPort(hXcv, cmd_ConfigureLPTPortCommandOKW, (PBYTE) num_1000000W, sizeof(num_1000000W), NULL, 0, &needed);
1009     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1010     needed = sizeof(buffer)-1 ;
1011     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) buffer, &needed);
1012     ok( (res == ERROR_SUCCESS) && (lstrcmpA(buffer, num_1000000A) == 0),
1013         "returned %d and '%s' (expected ERROR_SUCCESS and '%s')\n",
1014         res, buffer, num_1000000A);
1015 
1016     /*  using cmd_ConfigureLPTPortCommandOKW with does_not_existW:
1017         the string "does_not_exist" is written to the registry */
1018 
1019 
1020     /* restore the original value */
1021     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
1022     if (org_value[0]) {
1023         res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1);
1024         ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value);
1025     }
1026 
1027     RegCloseKey(hroot);
1028 
1029 }
1030 
1031 /* ########################### */
1032 
test_XcvDataPort_DeletePort(void)1033 static void test_XcvDataPort_DeletePort(void)
1034 {
1035     DWORD   res;
1036     DWORD   needed;
1037 
1038 
1039     /* cleanup: just to make sure */
1040     needed = (DWORD) 0xdeadbeef;
1041     SetLastError(0xdeadbeef);
1042     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1043     ok( !res  || (res == ERROR_FILE_NOT_FOUND),
1044         "returned %d with %u (expected ERROR_SUCCESS or ERROR_FILE_NOT_FOUND)\n",
1045         res, GetLastError());
1046 
1047 
1048     /* ToDo: cmd_AddPortW for tempfileW, then cmd_DeletePortW for the existing Port */
1049 
1050 
1051     /* try to delete a nonexistent Port */
1052     needed = (DWORD) 0xdeadbeef;
1053     SetLastError(0xdeadbeef);
1054     res = pXcvDataPort(hXcv, cmd_DeletePortW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1055     ok( res == ERROR_FILE_NOT_FOUND,
1056         "returned %d with %u (expected ERROR_FILE_NOT_FOUND)\n", res, GetLastError());
1057 
1058     /* emptyW as Portname: ERROR_FILE_NOT_FOUND is returned */
1059     /* NULL as Portname: Native localspl.dll crashed */
1060 
1061 }
1062 
1063 /* ########################### */
1064 
test_XcvDataPort_GetTransmissionRetryTimeout(void)1065 static void test_XcvDataPort_GetTransmissionRetryTimeout(void)
1066 {
1067     CHAR    org_value[16];
1068     HKEY    hroot = NULL;
1069     DWORD   buffer[2];
1070     DWORD   res;
1071     DWORD   needed;
1072     DWORD   len;
1073 
1074 
1075     /* ask for needed size */
1076     needed = (DWORD) 0xdeadbeef;
1077     SetLastError(0xdeadbeef);
1078     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, NULL, 0, &needed);
1079     if (res == ERROR_INVALID_PARAMETER) {
1080         skip("'GetTransmissionRetryTimeout' not supported\n");
1081         return;
1082     }
1083     len = sizeof(DWORD);
1084     ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed == len),
1085         "returned %d with %u and %u (expected ERROR_INSUFFICIENT_BUFFER "
1086         "and '%u')\n", res, GetLastError(), needed, len);
1087     len = needed;
1088 
1089     /* Read the original value from the registry */
1090     res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsA, 0, KEY_ALL_ACCESS, &hroot);
1091     if (res == ERROR_ACCESS_DENIED) {
1092         skip("ACCESS_DENIED\n");
1093         return;
1094     }
1095 
1096     if (res != ERROR_SUCCESS) {
1097         /* unable to open the registry: skip the test */
1098         skip("got %d\n", res);
1099         return;
1100     }
1101 
1102     org_value[0] = '\0';
1103     needed = sizeof(org_value)-1 ;
1104     res = RegQueryValueExA(hroot, TransmissionRetryTimeoutA, NULL, NULL, (PBYTE) org_value, &needed);
1105     ok( (res == ERROR_SUCCESS) || (res == ERROR_FILE_NOT_FOUND),
1106         "returned %u and %u for \"%s\" (expected ERROR_SUCCESS or "
1107         "ERROR_FILE_NOT_FOUND)\n", res, needed, org_value);
1108 
1109     /* Get default value (documented as 90 in the w2k reskit, but that is wrong) */
1110     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
1111     needed = (DWORD) 0xdeadbeef;
1112     buffer[0] = 0xdeadbeef;
1113     SetLastError(0xdeadbeef);
1114     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1115     ok( (res == ERROR_SUCCESS) && (buffer[0] == 45),
1116         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1117         "for '45')\n", res, GetLastError(), needed, buffer[0]);
1118 
1119     /* the default timeout is returned, when the value is empty */
1120     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)emptyA, 1);
1121     ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", GetLastError());
1122     needed = (DWORD) 0xdeadbeef;
1123     buffer[0] = 0xdeadbeef;
1124     SetLastError(0xdeadbeef);
1125     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1126     ok( (res == ERROR_SUCCESS) && (buffer[0] == 45),
1127         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1128         "for '45')\n", res, GetLastError(), needed, buffer[0]);
1129 
1130     /* the dialog is limited (1 - 999999), but that is done somewhere else */
1131     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_0A, lstrlenA(num_0A)+1);
1132     ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", GetLastError());
1133     needed = (DWORD) 0xdeadbeef;
1134     buffer[0] = 0xdeadbeef;
1135     SetLastError(0xdeadbeef);
1136     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1137     ok( (res == ERROR_SUCCESS) && (buffer[0] == 0),
1138         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1139         "for '0')\n", res, GetLastError(), needed, buffer[0]);
1140 
1141 
1142     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1A, lstrlenA(num_1A)+1);
1143     ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", GetLastError());
1144     needed = (DWORD) 0xdeadbeef;
1145     buffer[0] = 0xdeadbeef;
1146     SetLastError(0xdeadbeef);
1147     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1148     ok( (res == ERROR_SUCCESS) && (buffer[0] == 1),
1149         "returned %d with %u and %u for %d\n (expected 'ERROR_SUCCESS' "
1150         "for '1')\n", res, GetLastError(), needed, buffer[0]);
1151 
1152     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_999999A, lstrlenA(num_999999A)+1);
1153     ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", GetLastError());
1154     needed = (DWORD) 0xdeadbeef;
1155     buffer[0] = 0xdeadbeef;
1156     SetLastError(0xdeadbeef);
1157     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1158     ok( (res == ERROR_SUCCESS) && (buffer[0] == 999999),
1159         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1160         "for '999999')\n", res, GetLastError(), needed, buffer[0]);
1161 
1162 
1163     res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)num_1000000A, lstrlenA(num_1000000A)+1);
1164     ok(res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", GetLastError());
1165     needed = (DWORD) 0xdeadbeef;
1166     buffer[0] = 0xdeadbeef;
1167     SetLastError(0xdeadbeef);
1168     res = pXcvDataPort(hXcv, cmd_GetTransmissionRetryTimeoutW, NULL, 0, (PBYTE) buffer, len, &needed);
1169     ok( (res == ERROR_SUCCESS) && (buffer[0] == 1000000),
1170         "returned %d with %u and %u for %d\n (expected ERROR_SUCCESS "
1171         "for '1000000')\n", res, GetLastError(), needed, buffer[0]);
1172 
1173     /* restore the original value */
1174     RegDeleteValueA(hroot, TransmissionRetryTimeoutA);
1175     if (org_value[0]) {
1176         res = RegSetValueExA(hroot, TransmissionRetryTimeoutA, 0, REG_SZ, (PBYTE)org_value, lstrlenA(org_value)+1);
1177         ok(res == ERROR_SUCCESS, "unable to restore original value (got %u): %s\n", res, org_value);
1178     }
1179 
1180     RegCloseKey(hroot);
1181 }
1182 
1183 /* ########################### */
1184 
test_XcvDataPort_MonitorUI(void)1185 static void test_XcvDataPort_MonitorUI(void)
1186 {
1187     DWORD   res;
1188     BYTE    buffer[MAX_PATH + 2];
1189     DWORD   needed;
1190     DWORD   len;
1191 
1192 
1193     /* ask for needed size */
1194     needed = (DWORD) 0xdeadbeef;
1195     SetLastError(0xdeadbeef);
1196     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, 0, &needed);
1197     if (res == ERROR_INVALID_PARAMETER) {
1198         skip("'MonitorUI' nor supported\n");
1199         return;
1200     }
1201     ok( (res == ERROR_INSUFFICIENT_BUFFER) && (needed <= MAX_PATH),
1202         "returned %d with %u and 0x%x (expected 'ERROR_INSUFFICIENT_BUFFER' "
1203         " and '<= MAX_PATH')\n", res, GetLastError(), needed);
1204 
1205     if (needed > MAX_PATH) {
1206         skip("buffer overflow (%u)\n", needed);
1207         return;
1208     }
1209     len = needed;
1210 
1211     /* the command is required */
1212     needed = (DWORD) 0xdeadbeef;
1213     SetLastError(0xdeadbeef);
1214     res = pXcvDataPort(hXcv, emptyW, NULL, 0, NULL, 0, &needed);
1215     ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x "
1216         "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed);
1217 
1218     if (0) {
1219         /* crash with native localspl.dll (w2k+xp) */
1220         pXcvDataPort(hXcv, NULL, NULL, 0, buffer, MAX_PATH, &needed);
1221         pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, NULL, len, &needed);
1222         pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, NULL);
1223     }
1224 
1225 
1226     /* hXcv is ignored for the command "MonitorUI" */
1227     needed = (DWORD) 0xdeadbeef;
1228     SetLastError(0xdeadbeef);
1229     res = pXcvDataPort(NULL, cmd_MonitorUIW, NULL, 0, buffer, len, &needed);
1230     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1231         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1232 
1233 
1234     /* pszDataName is case-sensitive */
1235     memset(buffer, 0, len);
1236     needed = (DWORD) 0xdeadbeef;
1237     SetLastError(0xdeadbeef);
1238     res = pXcvDataPort(hXcv, cmd_MonitorUI_lcaseW, NULL, 0, buffer, len, &needed);
1239     ok( res == ERROR_INVALID_PARAMETER, "returned %d with %u and 0x%x "
1240         "(expected 'ERROR_INVALID_PARAMETER')\n", res, GetLastError(), needed);
1241 
1242     /* off by one: larger  */
1243     needed = (DWORD) 0xdeadbeef;
1244     SetLastError(0xdeadbeef);
1245     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len+1, &needed);
1246     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1247         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1248 
1249 
1250     /* off by one: smaller */
1251     /* the buffer is not modified for NT4, w2k, XP */
1252     needed = (DWORD) 0xdeadbeef;
1253     SetLastError(0xdeadbeef);
1254     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len-1, &needed);
1255     ok( res == ERROR_INSUFFICIENT_BUFFER, "returned %d with %u and 0x%x "
1256         "(expected 'ERROR_INSUFFICIENT_BUFFER')\n", res, GetLastError(), needed);
1257 
1258     /* Normal use. The DLL-Name without a Path is returned */
1259     memset(buffer, 0, len);
1260     needed = (DWORD) 0xdeadbeef;
1261     SetLastError(0xdeadbeef);
1262     res = pXcvDataPort(hXcv, cmd_MonitorUIW, NULL, 0, buffer, len, &needed);
1263     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1264         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1265 
1266 
1267     /* small check without access-rights: */
1268     if (!hXcv_noaccess) return;
1269 
1270     /* The ACCESS_MASK is ignored for "MonitorUI" */
1271     memset(buffer, 0, len);
1272     needed = (DWORD) 0xdeadbeef;
1273     SetLastError(0xdeadbeef);
1274     res = pXcvDataPort(hXcv_noaccess, cmd_MonitorUIW, NULL, 0, buffer, sizeof(buffer), &needed);
1275     ok( res == ERROR_SUCCESS, "returned %d with %u and 0x%x "
1276         "(expected 'ERROR_SUCCESS')\n", res, GetLastError(), needed);
1277 }
1278 
1279 /* ########################### */
1280 
test_XcvDataPort_PortIsValid(void)1281 static void test_XcvDataPort_PortIsValid(void)
1282 {
1283     DWORD   res;
1284     DWORD   needed;
1285 
1286     /* normal use: "LPT1:" */
1287     needed = (DWORD) 0xdeadbeef;
1288     SetLastError(0xdeadbeef);
1289     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed);
1290     if (res == ERROR_INVALID_PARAMETER) {
1291         skip("'PostIsValid' not supported\n");
1292         return;
1293     }
1294     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1295 
1296 
1297     if (0) {
1298         /* crash with native localspl.dll (w2k+xp) */
1299         pXcvDataPort(hXcv, cmd_PortIsValidW, NULL, 0, NULL, 0, &needed);
1300     }
1301 
1302 
1303     /* hXcv is ignored for the command "PortIsValid" */
1304     needed = (DWORD) 0xdeadbeef;
1305     SetLastError(0xdeadbeef);
1306     res = pXcvDataPort(NULL, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL);
1307     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1308 
1309     /* needed is ignored */
1310     needed = (DWORD) 0xdeadbeef;
1311     SetLastError(0xdeadbeef);
1312     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, NULL);
1313     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1314 
1315 
1316     /* cbInputData is ignored */
1317     needed = (DWORD) 0xdeadbeef;
1318     SetLastError(0xdeadbeef);
1319     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 0, NULL, 0, &needed);
1320     ok( res == ERROR_SUCCESS,
1321         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1322         res, GetLastError(), needed);
1323 
1324     needed = (DWORD) 0xdeadbeef;
1325     SetLastError(0xdeadbeef);
1326     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, 1, NULL, 0, &needed);
1327     ok( res == ERROR_SUCCESS,
1328         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1329         res, GetLastError(), needed);
1330 
1331     needed = (DWORD) 0xdeadbeef;
1332     SetLastError(0xdeadbeef);
1333     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -1, NULL, 0, &needed);
1334     ok( res == ERROR_SUCCESS,
1335         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1336         res, GetLastError(), needed);
1337 
1338     needed = (DWORD) 0xdeadbeef;
1339     SetLastError(0xdeadbeef);
1340     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W) -2, NULL, 0, &needed);
1341     ok( res == ERROR_SUCCESS,
1342         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1343         res, GetLastError(), needed);
1344 
1345 
1346     /* an empty name is not allowed */
1347     needed = (DWORD) 0xdeadbeef;
1348     SetLastError(0xdeadbeef);
1349     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) emptyW, sizeof(emptyW), NULL, 0, &needed);
1350     ok( res == ERROR_PATH_NOT_FOUND,
1351         "returned %d with %u and 0x%x (expected ERROR_PATH_NOT_FOUND)\n",
1352         res, GetLastError(), needed);
1353 
1354 
1355     /* a directory is not allowed */
1356     needed = (DWORD) 0xdeadbeef;
1357     SetLastError(0xdeadbeef);
1358     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempdirW, (lstrlenW(tempdirW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1359     /* XP(admin): ERROR_INVALID_NAME, XP(user): ERROR_PATH_NOT_FOUND, w2k ERROR_ACCESS_DENIED */
1360     ok( (res == ERROR_INVALID_NAME) || (res == ERROR_PATH_NOT_FOUND) ||
1361         (res == ERROR_ACCESS_DENIED), "returned %d with %u and 0x%x "
1362         "(expected ERROR_INVALID_NAME, ERROR_PATH_NOT_FOUND or ERROR_ACCESS_DENIED)\n",
1363         res, GetLastError(), needed);
1364 
1365 
1366     /* test more valid well known Ports: */
1367     needed = (DWORD) 0xdeadbeef;
1368     SetLastError(0xdeadbeef);
1369     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_lpt2W, sizeof(portname_lpt2W), NULL, 0, &needed);
1370     ok( res == ERROR_SUCCESS,
1371         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1372         res, GetLastError(), needed);
1373 
1374 
1375     needed = (DWORD) 0xdeadbeef;
1376     SetLastError(0xdeadbeef);
1377     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com1W, sizeof(portname_com1W), NULL, 0, &needed);
1378     ok( res == ERROR_SUCCESS,
1379         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1380         res, GetLastError(), needed);
1381 
1382 
1383     needed = (DWORD) 0xdeadbeef;
1384     SetLastError(0xdeadbeef);
1385     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_com2W, sizeof(portname_com2W), NULL, 0, &needed);
1386     ok( res == ERROR_SUCCESS,
1387         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1388         res, GetLastError(), needed);
1389 
1390 
1391     needed = (DWORD) 0xdeadbeef;
1392     SetLastError(0xdeadbeef);
1393     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) portname_fileW, sizeof(portname_fileW), NULL, 0, &needed);
1394     ok( res == ERROR_SUCCESS,
1395         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1396         res, GetLastError(), needed);
1397 
1398 
1399     /* a normal, writable file is allowed */
1400     needed = (DWORD) 0xdeadbeef;
1401     SetLastError(0xdeadbeef);
1402     res = pXcvDataPort(hXcv, cmd_PortIsValidW, (PBYTE) tempfileW, (lstrlenW(tempfileW) + 1) * sizeof(WCHAR), NULL, 0, &needed);
1403     ok( res == ERROR_SUCCESS,
1404         "returned %d with %u and 0x%x (expected ERROR_SUCCESS)\n",
1405         res, GetLastError(), needed);
1406 
1407 
1408     /* small check without access-rights: */
1409     if (!hXcv_noaccess) return;
1410 
1411     /* The ACCESS_MASK from XcvOpenPort is ignored in "PortIsValid" */
1412     needed = (DWORD) 0xdeadbeef;
1413     SetLastError(0xdeadbeef);
1414     res = pXcvDataPort(hXcv_noaccess, cmd_PortIsValidW, (PBYTE) portname_lpt1W, sizeof(portname_lpt1W), NULL, 0, &needed);
1415     ok( res == ERROR_SUCCESS, "returned %d with %u (expected ERROR_SUCCESS)\n", res, GetLastError());
1416 
1417 }
1418 
1419 /* ########################### */
1420 
test_XcvOpenPort(void)1421 static void test_XcvOpenPort(void)
1422 {
1423     DWORD   res;
1424     HANDLE  hXcv2;
1425 
1426 
1427     if (0)
1428     {
1429         /* crash with native localspl.dll (w2k+xp) */
1430         pXcvOpenPort(NULL, SERVER_ACCESS_ADMINISTER, &hXcv2);
1431         pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, NULL);
1432     }
1433 
1434 
1435     /* The returned handle is the result from a previous "spoolss.dll,DllAllocSplMem" */
1436     SetLastError(0xdeadbeef);
1437     hXcv2 = (HANDLE) 0xdeadbeef;
1438     res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv2);
1439     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1440     if (res) pXcvClosePort(hXcv2);
1441 
1442 
1443     /* The ACCESS_MASK is not checked in XcvOpenPort */
1444     SetLastError(0xdeadbeef);
1445     hXcv2 = (HANDLE) 0xdeadbeef;
1446     res = pXcvOpenPort(emptyW, 0, &hXcv2);
1447     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1448     if (res) pXcvClosePort(hXcv2);
1449 
1450 
1451     /* A copy of pszObject is saved in the Memory-Block */
1452     SetLastError(0xdeadbeef);
1453     hXcv2 = (HANDLE) 0xdeadbeef;
1454     res = pXcvOpenPort(portname_lpt1W, SERVER_ALL_ACCESS, &hXcv2);
1455     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1456     if (res) pXcvClosePort(hXcv2);
1457 
1458     SetLastError(0xdeadbeef);
1459     hXcv2 = (HANDLE) 0xdeadbeef;
1460     res = pXcvOpenPort(portname_fileW, SERVER_ALL_ACCESS, &hXcv2);
1461     ok(res, "returned %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv2);
1462     if (res) pXcvClosePort(hXcv2);
1463 
1464 }
1465 
1466 /* ########################### */
1467 
1468 #define GET_MONITOR_FUNC(name) \
1469     if (pm) p##name = pm->Monitor.pfn##name; \
1470     else if (pm2) p##name = pm2->pfn##name;
1471 
1472 #define GET_MONITOR_FUNC2(name) \
1473     if (pm) p##name = pm->Monitor.pfn##name; \
1474     else if (pm2) p##name##2 = pm2->pfn##name;
1475 
START_TEST(localmon)1476 START_TEST(localmon)
1477 {
1478     DWORD   numentries;
1479     DWORD   res;
1480 
1481     LoadLibraryA("winspool.drv");
1482     /* This DLL does not exist on Win9x */
1483     hdll = LoadLibraryA("localspl.dll");
1484     if (!hdll) {
1485         skip("localspl.dll cannot be loaded, most likely running on Win9x\n");
1486         return;
1487     }
1488 
1489     tempdirW[0] = '\0';
1490     tempfileW[0] = '\0';
1491     res = GetTempPathW(MAX_PATH, tempdirW);
1492     ok(res != 0, "with %u\n", GetLastError());
1493     res = GetTempFileNameW(tempdirW, wineW, 0, tempfileW);
1494     ok(res != 0, "with %u\n", GetLastError());
1495 
1496     pInitializePrintMonitor = (void *) GetProcAddress(hdll, "InitializePrintMonitor");
1497     pInitializePrintMonitor2 = (void *) GetProcAddress(hdll, "InitializePrintMonitor2");
1498 
1499     if (!pInitializePrintMonitor) {
1500         /* The Monitor for "Local Ports" was in a separate dll before w2k */
1501         hlocalmon = LoadLibraryA("localmon.dll");
1502         if (hlocalmon) {
1503             pInitializePrintMonitor = (void *) GetProcAddress(hlocalmon, "InitializePrintMonitor");
1504         }
1505     }
1506     if (!pInitializePrintMonitor && !pInitializePrintMonitor2) {
1507         skip("InitializePrintMonitor or InitializePrintMonitor2 not found\n");
1508         return;
1509     }
1510 
1511     /* Native localmon.dll / localspl.dll need a valid Port-Entry in:
1512        a) since xp: HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports
1513        b) up to w2k: Section "Ports" in win.ini
1514        or InitializePrintMonitor fails. */
1515     if (pInitializePrintMonitor)
1516         pm = pInitializePrintMonitor(Monitors_LocalPortW);
1517     else if (pInitializePrintMonitor2) {
1518         MONITORINIT init;
1519 
1520         memset(&init, 0, sizeof(init));
1521         init.cbSize = sizeof(init);
1522         init.hckRegistryRoot = 0;
1523         init.pMonitorReg = &monreg;
1524         init.bLocal = TRUE;
1525 
1526         pm2 = pInitializePrintMonitor2(&init, &hmon);
1527         ok(pm2 != NULL, "InitializePrintMonitor2 error %u\n", GetLastError());
1528         ok(pm2->cbSize >= FIELD_OFFSET(MONITOR2, pfnSendRecvBidiDataFromPort), "wrong cbSize %u\n", pm2->cbSize);
1529     }
1530 
1531     if (pm || pm2) {
1532         if (pm) {
1533             ok(pm->dwMonitorSize == sizeof(MONITOR), "wrong dwMonitorSize %u\n", pm->dwMonitorSize);
1534             numentries = (pm->dwMonitorSize ) / sizeof(VOID *);
1535             /* NT4: 14, since w2k: 17 */
1536             ok( numentries == 14 || numentries == 17,
1537                 "dwMonitorSize (%u) => %u Functions\n", pm->dwMonitorSize, numentries);
1538         }
1539         else if (pm2) {
1540             numentries = (pm2->cbSize ) / sizeof(VOID *);
1541             ok( numentries >= 20,
1542                 "cbSize (%u) => %u Functions\n", pm2->cbSize, numentries);
1543         }
1544 
1545         GET_MONITOR_FUNC2(EnumPorts);
1546         GET_MONITOR_FUNC2(OpenPort);
1547         GET_MONITOR_FUNC2(OpenPortEx);
1548         GET_MONITOR_FUNC(StartDocPort);
1549         GET_MONITOR_FUNC(WritePort);
1550         GET_MONITOR_FUNC(ReadPort);
1551         GET_MONITOR_FUNC(EndDocPort);
1552         GET_MONITOR_FUNC(ClosePort);
1553         GET_MONITOR_FUNC2(AddPort);
1554         GET_MONITOR_FUNC2(AddPortEx);
1555         GET_MONITOR_FUNC2(ConfigurePort);
1556         GET_MONITOR_FUNC2(DeletePort);
1557         GET_MONITOR_FUNC(GetPrinterDataFromPort);
1558         GET_MONITOR_FUNC(SetPortTimeOuts);
1559         GET_MONITOR_FUNC2(XcvOpenPort);
1560         GET_MONITOR_FUNC(XcvDataPort);
1561         GET_MONITOR_FUNC(XcvClosePort);
1562 
1563         if ((pXcvOpenPort) && (pXcvDataPort) && (pXcvClosePort)) {
1564             SetLastError(0xdeadbeef);
1565             res = pXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
1566             ok(res, "hXcv: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv);
1567 
1568             SetLastError(0xdeadbeef);
1569             res = pXcvOpenPort(emptyW, 0, &hXcv_noaccess);
1570             ok(res, "hXcv_noaccess: %d with %u and %p (expected '!= 0')\n", res, GetLastError(), hXcv_noaccess);
1571         }
1572     }
1573 
1574     test_InitializePrintMonitor();
1575     test_InitializePrintMonitor2();
1576 
1577     find_installed_ports();
1578 
1579     test_AddPort();
1580     test_AddPortEx();
1581     test_ClosePort();
1582     test_ConfigurePort();
1583     test_DeletePort();
1584     test_EnumPorts();
1585     test_OpenPort();
1586 
1587     if ( !hXcv ) {
1588         skip("Xcv not supported\n");
1589     }
1590     else
1591     {
1592         test_XcvClosePort();
1593         test_XcvDataPort_AddPort();
1594         test_XcvDataPort_ConfigureLPTPortCommandOK();
1595         test_XcvDataPort_DeletePort();
1596         test_XcvDataPort_GetTransmissionRetryTimeout();
1597         test_XcvDataPort_MonitorUI();
1598         test_XcvDataPort_PortIsValid();
1599         test_XcvOpenPort();
1600 
1601         pXcvClosePort(hXcv);
1602     }
1603     if (hXcv_noaccess) pXcvClosePort(hXcv_noaccess);
1604 
1605     /* Cleanup our temporary file */
1606     DeleteFileW(tempfileW);
1607 }
1608