Sunc with trunk revision 58971.
[reactos.git] / dll / win32 / localspl / localmon.c
1 /*
2 * Implementation of the Local Printmonitor
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 #define WIN32_NO_STATUS
22
23 #include <stdarg.h>
24
25 #define COBJMACROS
26 #define NONAMELESSUNION
27
28 #include <windef.h>
29 #include <winbase.h>
30 #include <wingdi.h>
31 #include <winuser.h>
32 #include <winreg.h>
33
34 #include <winspool.h>
35 #include <ddk/winsplp.h>
36 #include "localspl_private.h"
37
38 #include <wine/debug.h>
39 #include <wine/list.h>
40 #include <wine/unicode.h>
41
42
43 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
44
45 /*****************************************************/
46
47 static CRITICAL_SECTION port_handles_cs;
48 static CRITICAL_SECTION_DEBUG port_handles_cs_debug =
49 {
50 0, 0, &port_handles_cs,
51 { &port_handles_cs_debug.ProcessLocksList, &port_handles_cs_debug.ProcessLocksList },
52 0, 0, { (DWORD_PTR)(__FILE__ ": port_handles_cs") }
53 };
54 static CRITICAL_SECTION port_handles_cs = { &port_handles_cs_debug, -1, 0, 0, 0, 0 };
55
56
57 static CRITICAL_SECTION xcv_handles_cs;
58 static CRITICAL_SECTION_DEBUG xcv_handles_cs_debug =
59 {
60 0, 0, &xcv_handles_cs,
61 { &xcv_handles_cs_debug.ProcessLocksList, &xcv_handles_cs_debug.ProcessLocksList },
62 0, 0, { (DWORD_PTR)(__FILE__ ": xcv_handles_cs") }
63 };
64 static CRITICAL_SECTION xcv_handles_cs = { &xcv_handles_cs_debug, -1, 0, 0, 0, 0 };
65
66 /* ############################### */
67
68 typedef struct {
69 struct list entry;
70 DWORD type;
71 WCHAR nameW[1];
72 } port_t;
73
74 typedef struct {
75 struct list entry;
76 ACCESS_MASK GrantedAccess;
77 WCHAR nameW[1];
78 } xcv_t;
79
80 static struct list port_handles = LIST_INIT( port_handles );
81 static struct list xcv_handles = LIST_INIT( xcv_handles );
82
83 /* ############################### */
84
85 static const WCHAR cmd_AddPortW[] = {'A','d','d','P','o','r','t',0};
86 static const WCHAR cmd_DeletePortW[] = {'D','e','l','e','t','e','P','o','r','t',0};
87 static const WCHAR cmd_ConfigureLPTPortCommandOKW[] = {'C','o','n','f','i','g','u','r','e',
88 'L','P','T','P','o','r','t',
89 'C','o','m','m','a','n','d','O','K',0};
90
91 static const WCHAR cmd_GetDefaultCommConfigW[] = {'G','e','t',
92 'D','e','f','a','u','l','t',
93 'C','o','m','m','C','o','n','f','i','g',0};
94
95 static const WCHAR cmd_GetTransmissionRetryTimeoutW[] = {'G','e','t',
96 'T','r','a','n','s','m','i','s','s','i','o','n',
97 'R','e','t','r','y','T','i','m','e','o','u','t',0};
98
99 static const WCHAR cmd_MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
100 static const WCHAR cmd_PortIsValidW[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
101 static const WCHAR cmd_SetDefaultCommConfigW[] = {'S','e','t',
102 'D','e','f','a','u','l','t',
103 'C','o','m','m','C','o','n','f','i','g',0};
104
105 static const WCHAR dllnameuiW[] = {'l','o','c','a','l','u','i','.','d','l','l',0};
106 static const WCHAR emptyW[] = {0};
107 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
108
109 static const WCHAR portname_LPT[] = {'L','P','T',0};
110 static const WCHAR portname_COM[] = {'C','O','M',0};
111 static const WCHAR portname_FILE[] = {'F','I','L','E',':',0};
112 static const WCHAR portname_CUPS[] = {'C','U','P','S',':',0};
113 static const WCHAR portname_LPR[] = {'L','P','R',':',0};
114
115 static const WCHAR TransmissionRetryTimeoutW[] = {'T','r','a','n','s','m','i','s','s','i','o','n',
116 'R','e','t','r','y','T','i','m','e','o','u','t',0};
117
118 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
119 'M','i','c','r','o','s','o','f','t','\\',
120 'W','i','n','d','o','w','s',' ','N','T','\\',
121 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
122 'P','o','r','t','s',0};
123
124 static const WCHAR WinNT_CV_WindowsW[] = {'S','o','f','t','w','a','r','e','\\',
125 'M','i','c','r','o','s','o','f','t','\\',
126 'W','i','n','d','o','w','s',' ','N','T','\\',
127 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
128 'W','i','n','d','o','w','s',0};
129
130
131 /******************************************************************
132 * does_port_exist (internal)
133 *
134 * returns TRUE, when the Port already exists
135 *
136 */
137 static BOOL does_port_exist(LPCWSTR myname)
138 {
139
140 LPPORT_INFO_1W pi;
141 DWORD needed = 0;
142 DWORD returned;
143 DWORD id;
144
145 TRACE("(%s)\n", debugstr_w(myname));
146
147 id = EnumPortsW(NULL, 1, NULL, 0, &needed, &returned);
148 pi = heap_alloc(needed);
149 returned = 0;
150 if (pi)
151 id = EnumPortsW(NULL, 1, (LPBYTE) pi, needed, &needed, &returned);
152
153 if (id && returned > 0) {
154 /* we got a number of valid names. */
155 for (id = 0; id < returned; id++)
156 {
157 if (lstrcmpiW(myname, pi[id].pName) == 0) {
158 TRACE("(%u) found %s\n", id, debugstr_w(pi[id].pName));
159 heap_free(pi);
160 return TRUE;
161 }
162 }
163 }
164
165 heap_free(pi);
166 return FALSE;
167 }
168
169 /******************************************************************
170 * enumerate the local Ports from the Registry (internal)
171 *
172 * See localmon_EnumPortsW.
173 *
174 * NOTES
175 * returns the needed size (in bytes) for pPorts
176 * and *lpreturned is set to number of entries returned in pPorts
177 *
178 */
179
180 static DWORD get_ports_from_reg(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
181 {
182 HKEY hroot = 0;
183 LPWSTR ptr;
184 LPPORT_INFO_2W out;
185 WCHAR portname[MAX_PATH];
186 WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
187 WCHAR res_MonitorW[IDS_LOCALMONITOR_MAXLEN];
188 INT reslen_PortW;
189 INT reslen_MonitorW;
190 DWORD len;
191 DWORD res;
192 DWORD needed = 0;
193 DWORD numentries;
194 DWORD entrysize;
195 DWORD id = 0;
196
197 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
198
199 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
200
201 numentries = *lpreturned; /* this is 0, when we scan the registry */
202 needed = entrysize * numentries;
203 ptr = (LPWSTR) &pPorts[needed];
204
205 if (needed > cbBuf) pPorts = NULL; /* No buffer for the structs */
206
207 numentries = 0;
208 needed = 0;
209
210 /* we do not check more parameters as done in windows */
211 if ((level < 1) || (level > 2)) {
212 goto getports_cleanup;
213 }
214
215 /* "+1" for '\0' */
216 reslen_MonitorW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALMONITOR, res_MonitorW, IDS_LOCALMONITOR_MAXLEN) + 1;
217 reslen_PortW = LoadStringW(LOCALSPL_hInstance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN) + 1;
218
219 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
220 if (res == ERROR_SUCCESS) {
221
222 /* Scan all Port-Names */
223 while (res == ERROR_SUCCESS) {
224 len = MAX_PATH;
225 portname[0] = '\0';
226 res = RegEnumValueW(hroot, id, portname, &len, NULL, NULL, NULL, NULL);
227
228 if ((res == ERROR_SUCCESS) && (portname[0])) {
229 numentries++;
230 /* calculate the required size */
231 needed += entrysize;
232 needed += (len + 1) * sizeof(WCHAR);
233 if (level > 1) {
234 needed += (reslen_MonitorW + reslen_PortW) * sizeof(WCHAR);
235 }
236
237 /* Now fill the user-buffer, if available */
238 if (pPorts && (cbBuf >= needed)){
239 out = (LPPORT_INFO_2W) pPorts;
240 pPorts += entrysize;
241 TRACE("%p: writing PORT_INFO_%dW #%d (%s)\n", out, level, numentries, debugstr_w(portname));
242 out->pPortName = ptr;
243 lstrcpyW(ptr, portname); /* Name of the Port */
244 ptr += (len + 1);
245 if (level > 1) {
246 out->pMonitorName = ptr;
247 lstrcpyW(ptr, res_MonitorW); /* Name of the Monitor */
248 ptr += reslen_MonitorW;
249
250 out->pDescription = ptr;
251 lstrcpyW(ptr, res_PortW); /* Port Description */
252 ptr += reslen_PortW;
253
254 out->fPortType = PORT_TYPE_WRITE;
255 out->Reserved = 0;
256 }
257 }
258 id++;
259 }
260 }
261 RegCloseKey(hroot);
262 }
263 else
264 {
265 ERR("failed with %d for %s\n", res, debugstr_w(WinNT_CV_PortsW));
266 SetLastError(res);
267 }
268
269 getports_cleanup:
270 *lpreturned = numentries;
271 TRACE("need %d byte for %d entries (%d)\n", needed, numentries, GetLastError());
272 return needed;
273 }
274
275 /*****************************************************
276 * get_type_from_name (internal)
277 *
278 */
279
280 static DWORD get_type_from_name(LPCWSTR name)
281 {
282 HANDLE hfile;
283
284 if (!strncmpW(name, portname_LPT, sizeof(portname_LPT) / sizeof(WCHAR) -1))
285 return PORT_IS_LPT;
286
287 if (!strncmpW(name, portname_COM, sizeof(portname_COM) / sizeof(WCHAR) -1))
288 return PORT_IS_COM;
289
290 if (!strcmpW(name, portname_FILE))
291 return PORT_IS_FILE;
292
293 if (name[0] == '/')
294 return PORT_IS_UNIXNAME;
295
296 if (name[0] == '|')
297 return PORT_IS_PIPE;
298
299 if (!strncmpW(name, portname_CUPS, sizeof(portname_CUPS) / sizeof(WCHAR) -1))
300 return PORT_IS_CUPS;
301
302 if (!strncmpW(name, portname_LPR, sizeof(portname_LPR) / sizeof(WCHAR) -1))
303 return PORT_IS_LPR;
304
305 /* Must be a file or a directory. Does the file exist ? */
306 hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
307 TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name));
308 if (hfile == INVALID_HANDLE_VALUE) {
309 /* Can we create the file? */
310 hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
311 TRACE("%p for OPEN_ALWAYS\n", hfile);
312 }
313 if (hfile != INVALID_HANDLE_VALUE) {
314 CloseHandle(hfile);
315 return PORT_IS_FILENAME;
316 }
317 /* We can't use the name. use GetLastError() for the reason */
318 return PORT_IS_UNKNOWN;
319 }
320
321 /*****************************************************
322 * get_type_from_local_name (internal)
323 *
324 */
325
326 static DWORD get_type_from_local_name(LPCWSTR nameW)
327 {
328 LPPORT_INFO_1W pi;
329 LPWSTR myname = NULL;
330 DWORD needed = 0;
331 DWORD numentries = 0;
332 DWORD id = 0;
333
334 TRACE("(%s)\n", debugstr_w(myname));
335
336 needed = get_ports_from_reg(1, NULL, 0, &numentries);
337 pi = heap_alloc(needed);
338 if (pi)
339 needed = get_ports_from_reg(1, (LPBYTE) pi, needed, &numentries);
340
341 if (pi && needed && numentries > 0) {
342 /* we got a number of valid ports. */
343
344 while ((myname == NULL) && (id < numentries))
345 {
346 if (lstrcmpiW(nameW, pi[id].pName) == 0) {
347 TRACE("(%u) found %s\n", id, debugstr_w(pi[id].pName));
348 myname = pi[id].pName;
349 }
350 id++;
351 }
352 }
353
354 id = (myname) ? get_type_from_name(myname) : PORT_IS_UNKNOWN;
355
356 heap_free(pi);
357 return id;
358
359 }
360 /******************************************************************************
361 * localmon_AddPortExW [exported through MONITOREX]
362 *
363 * Add a Port, without presenting a user interface
364 *
365 * PARAMS
366 * pName [I] Servername or NULL (local Computer)
367 * level [I] Structure-Level (1) for pBuffer
368 * pBuffer [I] PTR to the Input-Data (PORT_INFO_1)
369 * pMonitorName [I] Name of the Monitor that manage the Port
370 *
371 * RETURNS
372 * Success: TRUE
373 * Failure: FALSE
374 *
375 * NOTES
376 * Level 2 is documented on MSDN for Portmonitors, but not supported by the
377 * "Local Port" Portmonitor (localspl.dll / localmon.dll)
378 */
379 static BOOL WINAPI localmon_AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
380 {
381 PORT_INFO_1W * pi;
382 HKEY hroot;
383 DWORD res;
384
385 pi = (PORT_INFO_1W *) pBuffer;
386 TRACE("(%s, %d, %p, %s) => %s\n", debugstr_w(pName), level, pBuffer,
387 debugstr_w(pMonitorName), debugstr_w(pi ? pi->pName : NULL));
388
389
390 if ((pMonitorName == NULL) || (lstrcmpiW(pMonitorName, LocalPortW) != 0 ) ||
391 (pi == NULL) || (pi->pName == NULL) || (pi->pName[0] == '\0') ) {
392 SetLastError(ERROR_INVALID_PARAMETER);
393 return FALSE;
394 }
395
396 if (level != 1) {
397 SetLastError(ERROR_INVALID_LEVEL);
398 return FALSE;
399 }
400
401 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
402 if (res == ERROR_SUCCESS) {
403 if (does_port_exist(pi->pName)) {
404 RegCloseKey(hroot);
405 TRACE("=> FALSE with %u\n", ERROR_INVALID_PARAMETER);
406 SetLastError(ERROR_INVALID_PARAMETER);
407 return FALSE;
408 }
409 res = RegSetValueExW(hroot, pi->pName, 0, REG_SZ, (const BYTE *) emptyW, sizeof(emptyW));
410 RegCloseKey(hroot);
411 }
412 if (res != ERROR_SUCCESS) SetLastError(ERROR_INVALID_PARAMETER);
413 TRACE("=> %u with %u\n", (res == ERROR_SUCCESS), GetLastError());
414 return (res == ERROR_SUCCESS);
415 }
416
417 /*****************************************************
418 * localmon_ClosePort [exported through MONITOREX]
419 *
420 * Close a
421 *
422 * PARAMS
423 * hPort [i] The Handle to close
424 *
425 * RETURNS
426 * Success: TRUE
427 * Failure: FALSE
428 *
429 */
430 static BOOL WINAPI localmon_ClosePort(HANDLE hPort)
431 {
432 port_t * port = hPort;
433
434 TRACE("(%p)\n", port);
435 EnterCriticalSection(&port_handles_cs);
436 list_remove(&port->entry);
437 LeaveCriticalSection(&port_handles_cs);
438 heap_free(port);
439 return TRUE;
440 }
441
442 /*****************************************************
443 * localmon_EnumPortsW [exported through MONITOREX]
444 *
445 * Enumerate all local Ports
446 *
447 * PARAMS
448 * pName [I] Servername (ignored)
449 * level [I] Structure-Level (1 or 2)
450 * pPorts [O] PTR to Buffer that receives the Result
451 * cbBuf [I] Size of Buffer at pPorts
452 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
453 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
454 *
455 * RETURNS
456 * Success: TRUE
457 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
458 *
459 * NOTES
460 *| Windows ignores pName
461 *| Windows crash the app, when pPorts, pcbNeeded or pcReturned are NULL
462 *| Windows >NT4.0 does not check for illegal levels (TRUE is returned)
463 *
464 * ToDo
465 * "HCU\Software\Wine\Spooler\<portname>" - redirection
466 *
467 */
468 static BOOL WINAPI localmon_EnumPortsW(LPWSTR pName, DWORD level, LPBYTE pPorts,
469 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
470 {
471 BOOL res = FALSE;
472 DWORD needed;
473 DWORD numentries;
474
475 TRACE("(%s, %d, %p, %d, %p, %p)\n",
476 debugstr_w(pName), level, pPorts, cbBuf, pcbNeeded, pcReturned);
477
478 numentries = 0;
479 needed = get_ports_from_reg(level, NULL, 0, &numentries);
480 /* we calculated the needed buffersize. now do the error-checks */
481 if (cbBuf < needed) {
482 SetLastError(ERROR_INSUFFICIENT_BUFFER);
483 goto cleanup;
484 }
485
486 /* fill the buffer with the Port-Names */
487 needed = get_ports_from_reg(level, pPorts, cbBuf, &numentries);
488 res = TRUE;
489
490 if (pcReturned) *pcReturned = numentries;
491
492 cleanup:
493 if (pcbNeeded) *pcbNeeded = needed;
494
495 TRACE("returning %d with %d (%d byte for %d entries)\n",
496 res, GetLastError(), needed, numentries);
497
498 return (res);
499 }
500
501 /*****************************************************
502 * localmon_OpenPort [exported through MONITOREX]
503 *
504 * Open a Data-Channel for a Port
505 *
506 * PARAMS
507 * pName [i] Name of selected Object
508 * phPort [o] The resulting Handle is stored here
509 *
510 * RETURNS
511 * Success: TRUE
512 * Failure: FALSE
513 *
514 */
515 static BOOL WINAPI localmon_OpenPortW(LPWSTR pName, PHANDLE phPort)
516 {
517 port_t * port;
518 DWORD len;
519 DWORD type;
520
521 TRACE("%s, %p)\n", debugstr_w(pName), phPort);
522
523 /* an empty name is invalid */
524 if (!pName[0]) return FALSE;
525
526 /* does the port exist? */
527 type = get_type_from_local_name(pName);
528 if (!type) return FALSE;
529
530 len = (lstrlenW(pName) + 1) * sizeof(WCHAR);
531 port = heap_alloc(sizeof(port_t) + len);
532 if (!port) return FALSE;
533
534 port->type = type;
535 memcpy(port->nameW, pName, len);
536 *phPort = port;
537
538 EnterCriticalSection(&port_handles_cs);
539 list_add_tail(&port_handles, &port->entry);
540 LeaveCriticalSection(&port_handles_cs);
541
542 TRACE("=> %p\n", port);
543 return TRUE;
544 }
545
546 /*****************************************************
547 * localmon_XcvClosePort [exported through MONITOREX]
548 *
549 * Close a Communication-Channel
550 *
551 * PARAMS
552 * hXcv [i] The Handle to close
553 *
554 * RETURNS
555 * Success: TRUE
556 * Failure: FALSE
557 *
558 */
559 static BOOL WINAPI localmon_XcvClosePort(HANDLE hXcv)
560 {
561 xcv_t * xcv = hXcv;
562
563 TRACE("(%p)\n", xcv);
564 /* No checks are done in Windows */
565 EnterCriticalSection(&xcv_handles_cs);
566 list_remove(&xcv->entry);
567 LeaveCriticalSection(&xcv_handles_cs);
568 heap_free(xcv);
569 return TRUE;
570 }
571
572 /*****************************************************
573 * localmon_XcvDataPort [exported through MONITOREX]
574 *
575 * Execute command through a Communication-Channel
576 *
577 * PARAMS
578 * hXcv [i] The Handle to work with
579 * pszDataName [i] Name of the command to execute
580 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
581 * cbInputData [i] Size in Bytes of Buffer at pInputData
582 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
583 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
584 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
585 *
586 * RETURNS
587 * Success: ERROR_SUCCESS
588 * Failure: win32 error code
589 *
590 * NOTES
591 *
592 * Minimal List of commands, that every Printmonitor DLL should support:
593 *
594 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
595 *| "AddPort" : Add a Port (Name as WSTR in pInputData)
596 *| "DeletePort": Delete a Port (Name as WSTR in pInputData)
597 *
598 *
599 */
600 static DWORD WINAPI localmon_XcvDataPort(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData,
601 PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
602 {
603 WCHAR buffer[16]; /* buffer for a decimal number */
604 LPWSTR ptr;
605 DWORD res;
606 DWORD needed;
607 HKEY hroot;
608
609 TRACE("(%p, %s, %p, %d, %p, %d, %p)\n", hXcv, debugstr_w(pszDataName),
610 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
611
612 if (!lstrcmpW(pszDataName, cmd_AddPortW)) {
613 TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
614 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
615 if (res == ERROR_SUCCESS) {
616 if (does_port_exist((LPWSTR) pInputData)) {
617 RegCloseKey(hroot);
618 TRACE("=> %u\n", ERROR_ALREADY_EXISTS);
619 return ERROR_ALREADY_EXISTS;
620 }
621 res = RegSetValueExW(hroot, (LPWSTR) pInputData, 0, REG_SZ, (const BYTE *) emptyW, sizeof(emptyW));
622 RegCloseKey(hroot);
623 }
624 TRACE("=> %u\n", res);
625 return res;
626 }
627
628
629 if (!lstrcmpW(pszDataName, cmd_ConfigureLPTPortCommandOKW)) {
630 TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
631 res = RegCreateKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsW, &hroot);
632 if (res == ERROR_SUCCESS) {
633 res = RegSetValueExW(hroot, TransmissionRetryTimeoutW, 0, REG_SZ, pInputData, cbInputData);
634 RegCloseKey(hroot);
635 }
636 return res;
637 }
638
639 if (!lstrcmpW(pszDataName, cmd_DeletePortW)) {
640 TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
641 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
642 if (res == ERROR_SUCCESS) {
643 res = RegDeleteValueW(hroot, (LPWSTR) pInputData);
644 RegCloseKey(hroot);
645 TRACE("=> %u with %u\n", res, GetLastError() );
646 return res;
647 }
648 return ERROR_FILE_NOT_FOUND;
649 }
650
651 if (!lstrcmpW(pszDataName, cmd_GetDefaultCommConfigW)) {
652 TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
653 *pcbOutputNeeded = cbOutputData;
654 res = GetDefaultCommConfigW((LPWSTR) pInputData, (LPCOMMCONFIG) pOutputData, pcbOutputNeeded);
655 TRACE("got %u with %u\n", res, GetLastError() );
656 return res ? ERROR_SUCCESS : GetLastError();
657 }
658
659 if (!lstrcmpW(pszDataName, cmd_GetTransmissionRetryTimeoutW)) {
660 * pcbOutputNeeded = sizeof(DWORD);
661 if (cbOutputData >= sizeof(DWORD)) {
662 /* the w2k resource kit documented a default of 90, but that's wrong */
663 *((LPDWORD) pOutputData) = 45;
664
665 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsW, &hroot);
666 if (res == ERROR_SUCCESS) {
667 needed = sizeof(buffer) - sizeof(WCHAR);
668 res = RegQueryValueExW(hroot, TransmissionRetryTimeoutW, NULL, NULL, (LPBYTE) buffer, &needed);
669 if ((res == ERROR_SUCCESS) && (buffer[0])) {
670 *((LPDWORD) pOutputData) = strtoulW(buffer, NULL, 0);
671 }
672 RegCloseKey(hroot);
673 }
674 return ERROR_SUCCESS;
675 }
676 return ERROR_INSUFFICIENT_BUFFER;
677 }
678
679
680 if (!lstrcmpW(pszDataName, cmd_MonitorUIW)) {
681 * pcbOutputNeeded = sizeof(dllnameuiW);
682 if (cbOutputData >= sizeof(dllnameuiW)) {
683 memcpy(pOutputData, dllnameuiW, sizeof(dllnameuiW));
684 return ERROR_SUCCESS;
685 }
686 return ERROR_INSUFFICIENT_BUFFER;
687 }
688
689 if (!lstrcmpW(pszDataName, cmd_PortIsValidW)) {
690 TRACE("InputData (%d): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
691 res = get_type_from_name((LPCWSTR) pInputData);
692 TRACE("detected as %u\n", res);
693 /* names, that we have recognized, are valid */
694 if (res) return ERROR_SUCCESS;
695
696 /* ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND or something else */
697 TRACE("=> %u\n", GetLastError());
698 return GetLastError();
699 }
700
701 if (!lstrcmpW(pszDataName, cmd_SetDefaultCommConfigW)) {
702 /* get the portname from the Handle */
703 ptr = strchrW(((xcv_t *)hXcv)->nameW, ' ');
704 if (ptr) {
705 ptr++; /* skip the space */
706 }
707 else
708 {
709 ptr = ((xcv_t *)hXcv)->nameW;
710 }
711 lstrcpynW(buffer, ptr, sizeof(buffer)/sizeof(WCHAR));
712 if (buffer[0]) buffer[lstrlenW(buffer)-1] = '\0'; /* remove the ':' */
713 res = SetDefaultCommConfigW(buffer, (LPCOMMCONFIG) pInputData, cbInputData);
714 TRACE("got %u with %u\n", res, GetLastError() );
715 return res ? ERROR_SUCCESS : GetLastError();
716 }
717
718 FIXME("command not supported: %s\n", debugstr_w(pszDataName));
719 return ERROR_INVALID_PARAMETER;
720 }
721
722 /*****************************************************
723 * localmon_XcvOpenPort [exported through MONITOREX]
724 *
725 * Open a Communication-Channel
726 *
727 * PARAMS
728 * pName [i] Name of selected Object
729 * GrantedAccess [i] Access-Rights to use
730 * phXcv [o] The resulting Handle is stored here
731 *
732 * RETURNS
733 * Success: TRUE
734 * Failure: FALSE
735 *
736 */
737 static BOOL WINAPI localmon_XcvOpenPort(LPCWSTR pName, ACCESS_MASK GrantedAccess, PHANDLE phXcv)
738 {
739 DWORD len;
740 xcv_t * xcv;
741
742 TRACE("%s, 0x%x, %p)\n", debugstr_w(pName), GrantedAccess, phXcv);
743 /* No checks for any field is done in Windows */
744 len = (lstrlenW(pName) + 1) * sizeof(WCHAR);
745 xcv = heap_alloc( sizeof(xcv_t) + len);
746 if (xcv) {
747 xcv->GrantedAccess = GrantedAccess;
748 memcpy(xcv->nameW, pName, len);
749 *phXcv = xcv;
750 EnterCriticalSection(&xcv_handles_cs);
751 list_add_tail(&xcv_handles, &xcv->entry);
752 LeaveCriticalSection(&xcv_handles_cs);
753 TRACE("=> %p\n", xcv);
754 return TRUE;
755 }
756 else
757 {
758 *phXcv = NULL;
759 return FALSE;
760 }
761 }
762
763 /*****************************************************
764 * InitializePrintMonitor (LOCALSPL.@)
765 *
766 * Initialize the Monitor for the Local Ports
767 *
768 * PARAMS
769 * regroot [I] Registry-Path, where the settings are stored
770 *
771 * RETURNS
772 * Success: Pointer to a MONITOREX Structure
773 * Failure: NULL
774 *
775 * NOTES
776 * The fixed location "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports"
777 * is used to store the Ports (IniFileMapping from "win.ini", Section "Ports").
778 * Native localspl.dll fails, when no valid Port-Entry is present.
779 *
780 */
781
782 LPMONITOREX WINAPI InitializePrintMonitor(LPWSTR regroot)
783 {
784 static MONITOREX mymonitorex =
785 {
786 sizeof(MONITOREX) - sizeof(DWORD),
787 {
788 localmon_EnumPortsW,
789 localmon_OpenPortW,
790 NULL, /* localmon_OpenPortExW */
791 NULL, /* localmon_StartDocPortW */
792 NULL, /* localmon_WritePortW */
793 NULL, /* localmon_ReadPortW */
794 NULL, /* localmon_EndDocPortW */
795 localmon_ClosePort,
796 NULL, /* Use AddPortUI in localui.dll */
797 localmon_AddPortExW,
798 NULL, /* Use ConfigurePortUI in localui.dll */
799 NULL, /* Use DeletePortUI in localui.dll */
800 NULL, /* localmon_GetPrinterDataFromPort */
801 NULL, /* localmon_SetPortTimeOuts */
802 localmon_XcvOpenPort,
803 localmon_XcvDataPort,
804 localmon_XcvClosePort
805 }
806 };
807
808 TRACE("(%s)\n", debugstr_w(regroot));
809 /* Parameter "regroot" is ignored on NT4.0 (localmon.dll) */
810 if (!regroot || !regroot[0]) {
811 SetLastError(ERROR_INVALID_PARAMETER);
812 return NULL;
813 }
814 TRACE("=> %p\n", &mymonitorex);
815 /* Native windows returns always the same pointer on success */
816 return &mymonitorex;
817 }