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