win32u: Use NT interface for MsgWaitForMultipleObjectsEx user driver entry point.
[wine.git] / dlls / localspl / localmon.c
blob5b64c7061eeb35452f5c2eca66bc38a001a4ecc2
1 /*
2 * Implementation of the Local Printmonitor
4 * Copyright 2006 Detlef Riekenberg
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.
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.
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
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winreg.h"
32 #include "winspool.h"
33 #include "ddk/winsplp.h"
34 #include "localspl_private.h"
36 #include "wine/debug.h"
37 #include "wine/heap.h"
38 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
43 /*****************************************************/
45 static CRITICAL_SECTION port_handles_cs;
46 static CRITICAL_SECTION_DEBUG port_handles_cs_debug =
48 0, 0, &port_handles_cs,
49 { &port_handles_cs_debug.ProcessLocksList, &port_handles_cs_debug.ProcessLocksList },
50 0, 0, { (DWORD_PTR)(__FILE__ ": port_handles_cs") }
52 static CRITICAL_SECTION port_handles_cs = { &port_handles_cs_debug, -1, 0, 0, 0, 0 };
55 static CRITICAL_SECTION xcv_handles_cs;
56 static CRITICAL_SECTION_DEBUG xcv_handles_cs_debug =
58 0, 0, &xcv_handles_cs,
59 { &xcv_handles_cs_debug.ProcessLocksList, &xcv_handles_cs_debug.ProcessLocksList },
60 0, 0, { (DWORD_PTR)(__FILE__ ": xcv_handles_cs") }
62 static CRITICAL_SECTION xcv_handles_cs = { &xcv_handles_cs_debug, -1, 0, 0, 0, 0 };
64 /* ############################### */
66 typedef struct {
67 struct list entry;
68 DWORD type;
69 WCHAR nameW[1];
70 } port_t;
72 typedef struct {
73 struct list entry;
74 ACCESS_MASK GrantedAccess;
75 WCHAR nameW[1];
76 } xcv_t;
78 static struct list port_handles = LIST_INIT( port_handles );
79 static struct list xcv_handles = LIST_INIT( xcv_handles );
81 static const WCHAR WinNT_CV_PortsW[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
82 static const WCHAR WinNT_CV_WindowsW[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
84 HINSTANCE localspl_instance;
86 /*****************************************************
87 * DllMain
89 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
91 TRACE("(%p, %ld, %p)\n",hinstDLL, fdwReason, lpvReserved);
93 switch(fdwReason)
95 case DLL_PROCESS_ATTACH:
96 DisableThreadLibraryCalls( hinstDLL );
97 localspl_instance = hinstDLL;
98 break;
100 return TRUE;
103 /******************************************************************
104 * does_port_exist (internal)
106 * returns TRUE, when the Port already exists
109 static BOOL does_port_exist(LPCWSTR myname)
112 LPPORT_INFO_1W pi;
113 DWORD needed = 0;
114 DWORD returned;
115 DWORD id;
117 TRACE("(%s)\n", debugstr_w(myname));
119 id = EnumPortsW(NULL, 1, NULL, 0, &needed, &returned);
120 pi = heap_alloc(needed);
121 returned = 0;
122 if (pi)
123 id = EnumPortsW(NULL, 1, (LPBYTE) pi, needed, &needed, &returned);
125 if (id && returned > 0) {
126 /* we got a number of valid names. */
127 for (id = 0; id < returned; id++)
129 if (lstrcmpiW(myname, pi[id].pName) == 0) {
130 TRACE("(%lu) found %s\n", id, debugstr_w(pi[id].pName));
131 heap_free(pi);
132 return TRUE;
137 heap_free(pi);
138 return FALSE;
141 /******************************************************************
142 * enumerate the local Ports from the Registry (internal)
144 * See localmon_EnumPortsW.
146 * NOTES
147 * returns the needed size (in bytes) for pPorts
148 * and *lpreturned is set to number of entries returned in pPorts
152 static DWORD get_ports_from_reg(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
154 HKEY hroot = 0;
155 LPWSTR ptr;
156 LPPORT_INFO_2W out;
157 WCHAR portname[MAX_PATH];
158 WCHAR res_PortW[IDS_LOCALPORT_MAXLEN];
159 WCHAR res_MonitorW[IDS_LOCALMONITOR_MAXLEN];
160 INT reslen_PortW;
161 INT reslen_MonitorW;
162 DWORD len;
163 DWORD res;
164 DWORD needed = 0;
165 DWORD numentries;
166 DWORD entrysize;
167 DWORD id = 0;
169 TRACE("(%ld, %p, %ld, %p)\n", level, pPorts, cbBuf, lpreturned);
171 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
173 numentries = *lpreturned; /* this is 0, when we scan the registry */
174 needed = entrysize * numentries;
175 ptr = (LPWSTR) &pPorts[needed];
177 if (needed > cbBuf) pPorts = NULL; /* No buffer for the structs */
179 numentries = 0;
180 needed = 0;
182 /* we do not check more parameters as done in windows */
183 if ((level < 1) || (level > 2)) {
184 goto getports_cleanup;
187 /* "+1" for '\0' */
188 reslen_MonitorW = LoadStringW(localspl_instance, IDS_LOCALMONITOR, res_MonitorW, IDS_LOCALMONITOR_MAXLEN) + 1;
189 reslen_PortW = LoadStringW(localspl_instance, IDS_LOCALPORT, res_PortW, IDS_LOCALPORT_MAXLEN) + 1;
191 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
192 if (res == ERROR_SUCCESS) {
194 /* Scan all Port-Names */
195 while (res == ERROR_SUCCESS) {
196 len = MAX_PATH;
197 portname[0] = '\0';
198 res = RegEnumValueW(hroot, id, portname, &len, NULL, NULL, NULL, NULL);
200 if ((res == ERROR_SUCCESS) && (portname[0])) {
201 numentries++;
202 /* calculate the required size */
203 needed += entrysize;
204 needed += (len + 1) * sizeof(WCHAR);
205 if (level > 1) {
206 needed += (reslen_MonitorW + reslen_PortW) * sizeof(WCHAR);
209 /* Now fill the user-buffer, if available */
210 if (pPorts && (cbBuf >= needed)){
211 out = (LPPORT_INFO_2W) pPorts;
212 pPorts += entrysize;
213 TRACE("%p: writing PORT_INFO_%ldW #%ld (%s)\n", out, level, numentries, debugstr_w(portname));
214 out->pPortName = ptr;
215 lstrcpyW(ptr, portname); /* Name of the Port */
216 ptr += (len + 1);
217 if (level > 1) {
218 out->pMonitorName = ptr;
219 lstrcpyW(ptr, res_MonitorW); /* Name of the Monitor */
220 ptr += reslen_MonitorW;
222 out->pDescription = ptr;
223 lstrcpyW(ptr, res_PortW); /* Port Description */
224 ptr += reslen_PortW;
226 out->fPortType = PORT_TYPE_WRITE;
227 out->Reserved = 0;
230 id++;
233 RegCloseKey(hroot);
235 else
237 ERR("failed with %ld for %s\n", res, debugstr_w(WinNT_CV_PortsW));
238 SetLastError(res);
241 getports_cleanup:
242 *lpreturned = numentries;
243 TRACE("need %ld byte for %ld entries (%ld)\n", needed, numentries, GetLastError());
244 return needed;
247 /*****************************************************
248 * get_type_from_name (internal)
252 static DWORD get_type_from_name(LPCWSTR name)
254 HANDLE hfile;
256 if (!wcsncmp(name, L"LPT", ARRAY_SIZE(L"LPT") - 1))
257 return PORT_IS_LPT;
259 if (!wcsncmp(name, L"COM", ARRAY_SIZE(L"COM") - 1))
260 return PORT_IS_COM;
262 if (!lstrcmpW(name, L"FILE:"))
263 return PORT_IS_FILE;
265 if (name[0] == '/')
266 return PORT_IS_UNIXNAME;
268 if (name[0] == '|')
269 return PORT_IS_PIPE;
271 if (!wcsncmp(name, L"CUPS:", ARRAY_SIZE(L"CUPS:") - 1))
272 return PORT_IS_CUPS;
274 if (!wcsncmp(name, L"LPR:", ARRAY_SIZE(L"LPR:") - 1))
275 return PORT_IS_LPR;
277 /* Must be a file or a directory. Does the file exist ? */
278 hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
279 TRACE("%p for OPEN_EXISTING on %s\n", hfile, debugstr_w(name));
280 if (hfile == INVALID_HANDLE_VALUE) {
281 /* Can we create the file? */
282 hfile = CreateFileW(name, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
283 TRACE("%p for OPEN_ALWAYS\n", hfile);
285 if (hfile != INVALID_HANDLE_VALUE) {
286 CloseHandle(hfile);
287 return PORT_IS_FILENAME;
289 /* We can't use the name. use GetLastError() for the reason */
290 return PORT_IS_UNKNOWN;
293 /*****************************************************
294 * get_type_from_local_name (internal)
298 static DWORD get_type_from_local_name(LPCWSTR nameW)
300 LPPORT_INFO_1W pi;
301 LPWSTR myname = NULL;
302 DWORD needed = 0;
303 DWORD numentries = 0;
304 DWORD id = 0;
306 TRACE("(%s)\n", debugstr_w(myname));
308 needed = get_ports_from_reg(1, NULL, 0, &numentries);
309 pi = heap_alloc(needed);
310 if (pi)
311 needed = get_ports_from_reg(1, (LPBYTE) pi, needed, &numentries);
313 if (pi && needed && numentries > 0) {
314 /* we got a number of valid ports. */
316 while ((myname == NULL) && (id < numentries))
318 if (lstrcmpiW(nameW, pi[id].pName) == 0) {
319 TRACE("(%lu) found %s\n", id, debugstr_w(pi[id].pName));
320 myname = pi[id].pName;
322 id++;
326 id = (myname) ? get_type_from_name(myname) : PORT_IS_UNKNOWN;
328 heap_free(pi);
329 return id;
332 /******************************************************************************
333 * localmon_AddPortExW [exported through MONITOREX]
335 * Add a Port, without presenting a user interface
337 * PARAMS
338 * pName [I] Servername or NULL (local Computer)
339 * level [I] Structure-Level (1) for pBuffer
340 * pBuffer [I] PTR to the Input-Data (PORT_INFO_1)
341 * pMonitorName [I] Name of the Monitor that manage the Port
343 * RETURNS
344 * Success: TRUE
345 * Failure: FALSE
347 * NOTES
348 * Level 2 is documented on MSDN for Portmonitors, but not supported by the
349 * "Local Port" Portmonitor (localspl.dll / localmon.dll)
351 static BOOL WINAPI localmon_AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
353 PORT_INFO_1W * pi;
354 HKEY hroot;
355 DWORD res;
357 pi = (PORT_INFO_1W *) pBuffer;
358 TRACE("(%s, %ld, %p, %s) => %s\n", debugstr_w(pName), level, pBuffer,
359 debugstr_w(pMonitorName), debugstr_w(pi ? pi->pName : NULL));
362 if ((pMonitorName == NULL) || (lstrcmpiW(pMonitorName, L"Local Port") != 0 ) ||
363 (pi == NULL) || (pi->pName == NULL) || (pi->pName[0] == '\0') ) {
364 SetLastError(ERROR_INVALID_PARAMETER);
365 return FALSE;
368 if (level != 1) {
369 SetLastError(ERROR_INVALID_LEVEL);
370 return FALSE;
373 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
374 if (res == ERROR_SUCCESS) {
375 if (does_port_exist(pi->pName)) {
376 RegCloseKey(hroot);
377 TRACE("=> FALSE with %u\n", ERROR_INVALID_PARAMETER);
378 SetLastError(ERROR_INVALID_PARAMETER);
379 return FALSE;
381 res = RegSetValueExW(hroot, pi->pName, 0, REG_SZ, (const BYTE *) L"", sizeof(L""));
382 RegCloseKey(hroot);
384 if (res != ERROR_SUCCESS) SetLastError(ERROR_INVALID_PARAMETER);
385 TRACE("=> %u with %lu\n", (res == ERROR_SUCCESS), GetLastError());
386 return (res == ERROR_SUCCESS);
389 /*****************************************************
390 * localmon_ClosePort [exported through MONITOREX]
392 * Close a
394 * PARAMS
395 * hPort [i] The Handle to close
397 * RETURNS
398 * Success: TRUE
399 * Failure: FALSE
402 static BOOL WINAPI localmon_ClosePort(HANDLE hPort)
404 port_t * port = hPort;
406 TRACE("(%p)\n", port);
407 EnterCriticalSection(&port_handles_cs);
408 list_remove(&port->entry);
409 LeaveCriticalSection(&port_handles_cs);
410 heap_free(port);
411 return TRUE;
414 /*****************************************************
415 * localmon_EnumPortsW [exported through MONITOREX]
417 * Enumerate all local Ports
419 * PARAMS
420 * pName [I] Servername (ignored)
421 * level [I] Structure-Level (1 or 2)
422 * pPorts [O] PTR to Buffer that receives the Result
423 * cbBuf [I] Size of Buffer at pPorts
424 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
425 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
427 * RETURNS
428 * Success: TRUE
429 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
431 * NOTES
432 *| Windows ignores pName
433 *| Windows crash the app, when pPorts, pcbNeeded or pcReturned are NULL
434 *| Windows >NT4.0 does not check for illegal levels (TRUE is returned)
436 * ToDo
437 * "HCU\Software\Wine\Spooler\<portname>" - redirection
440 static BOOL WINAPI localmon_EnumPortsW(LPWSTR pName, DWORD level, LPBYTE pPorts,
441 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
443 BOOL res = FALSE;
444 DWORD needed;
445 DWORD numentries;
447 TRACE("(%s, %ld, %p, %ld, %p, %p)\n",
448 debugstr_w(pName), level, pPorts, cbBuf, pcbNeeded, pcReturned);
450 numentries = 0;
451 needed = get_ports_from_reg(level, NULL, 0, &numentries);
452 /* we calculated the needed buffersize. now do the error-checks */
453 if (cbBuf < needed) {
454 SetLastError(ERROR_INSUFFICIENT_BUFFER);
455 goto cleanup;
458 /* fill the buffer with the Port-Names */
459 needed = get_ports_from_reg(level, pPorts, cbBuf, &numentries);
460 res = TRUE;
462 if (pcReturned) *pcReturned = numentries;
464 cleanup:
465 if (pcbNeeded) *pcbNeeded = needed;
467 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
468 res, GetLastError(), needed, numentries);
470 return (res);
473 /*****************************************************
474 * localmon_OpenPort [exported through MONITOREX]
476 * Open a Data-Channel for a Port
478 * PARAMS
479 * pName [i] Name of selected Object
480 * phPort [o] The resulting Handle is stored here
482 * RETURNS
483 * Success: TRUE
484 * Failure: FALSE
487 static BOOL WINAPI localmon_OpenPortW(LPWSTR pName, PHANDLE phPort)
489 port_t * port;
490 DWORD type;
492 TRACE("%s, %p)\n", debugstr_w(pName), phPort);
494 /* an empty name is invalid */
495 if (!pName[0]) return FALSE;
497 /* does the port exist? */
498 type = get_type_from_local_name(pName);
499 if (!type) return FALSE;
501 port = heap_alloc(FIELD_OFFSET(port_t, nameW[lstrlenW(pName) + 1]));
502 if (!port) return FALSE;
504 port->type = type;
505 lstrcpyW(port->nameW, pName);
506 *phPort = port;
508 EnterCriticalSection(&port_handles_cs);
509 list_add_tail(&port_handles, &port->entry);
510 LeaveCriticalSection(&port_handles_cs);
512 TRACE("=> %p\n", port);
513 return TRUE;
516 /*****************************************************
517 * localmon_XcvClosePort [exported through MONITOREX]
519 * Close a Communication-Channel
521 * PARAMS
522 * hXcv [i] The Handle to close
524 * RETURNS
525 * Success: TRUE
526 * Failure: FALSE
529 static BOOL WINAPI localmon_XcvClosePort(HANDLE hXcv)
531 xcv_t * xcv = hXcv;
533 TRACE("(%p)\n", xcv);
534 /* No checks are done in Windows */
535 EnterCriticalSection(&xcv_handles_cs);
536 list_remove(&xcv->entry);
537 LeaveCriticalSection(&xcv_handles_cs);
538 heap_free(xcv);
539 return TRUE;
542 /*****************************************************
543 * localmon_XcvDataPort [exported through MONITOREX]
545 * Execute command through a Communication-Channel
547 * PARAMS
548 * hXcv [i] The Handle to work with
549 * pszDataName [i] Name of the command to execute
550 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
551 * cbInputData [i] Size in Bytes of Buffer at pInputData
552 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
553 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
554 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
556 * RETURNS
557 * Success: ERROR_SUCCESS
558 * Failure: win32 error code
560 * NOTES
562 * Minimal List of commands, that every Printmonitor DLL should support:
564 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
565 *| "AddPort" : Add a Port (Name as WSTR in pInputData)
566 *| "DeletePort": Delete a Port (Name as WSTR in pInputData)
570 static DWORD WINAPI localmon_XcvDataPort(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData,
571 PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded)
573 WCHAR buffer[16]; /* buffer for a decimal number */
574 LPWSTR ptr;
575 DWORD res;
576 DWORD needed;
577 HKEY hroot;
579 TRACE("(%p, %s, %p, %ld, %p, %ld, %p)\n", hXcv, debugstr_w(pszDataName),
580 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
582 if (!lstrcmpW(pszDataName, L"AddPort")) {
583 TRACE("InputData (%ld): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
584 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
585 if (res == ERROR_SUCCESS) {
586 if (does_port_exist((LPWSTR) pInputData)) {
587 RegCloseKey(hroot);
588 TRACE("=> %u\n", ERROR_ALREADY_EXISTS);
589 return ERROR_ALREADY_EXISTS;
591 res = RegSetValueExW(hroot, (LPWSTR)pInputData, 0, REG_SZ, (const BYTE*)L"", sizeof(L""));
592 RegCloseKey(hroot);
594 TRACE("=> %lu\n", res);
595 return res;
599 if (!lstrcmpW(pszDataName, L"ConfigureLPTPortCommandOK")) {
600 TRACE("InputData (%ld): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
601 res = RegCreateKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsW, &hroot);
602 if (res == ERROR_SUCCESS) {
603 res = RegSetValueExW(hroot, L"TransmissionRetryTimeout", 0, REG_SZ, pInputData, cbInputData);
604 RegCloseKey(hroot);
606 return res;
609 if (!lstrcmpW(pszDataName, L"DeletePort")) {
610 TRACE("InputData (%ld): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
611 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot);
612 if (res == ERROR_SUCCESS) {
613 res = RegDeleteValueW(hroot, (LPWSTR) pInputData);
614 RegCloseKey(hroot);
615 TRACE("=> %lu with %lu\n", res, GetLastError() );
616 return res;
618 return ERROR_FILE_NOT_FOUND;
621 if (!lstrcmpW(pszDataName, L"GetDefaultCommConfig")) {
622 TRACE("InputData (%ld): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
623 *pcbOutputNeeded = cbOutputData;
624 res = GetDefaultCommConfigW((LPWSTR) pInputData, (LPCOMMCONFIG) pOutputData, pcbOutputNeeded);
625 TRACE("got %lu with %lu\n", res, GetLastError() );
626 return res ? ERROR_SUCCESS : GetLastError();
629 if (!lstrcmpW(pszDataName, L"GetTransmissionRetryTimeout")) {
630 * pcbOutputNeeded = sizeof(DWORD);
631 if (cbOutputData >= sizeof(DWORD)) {
632 /* the w2k resource kit documented a default of 90, but that's wrong */
633 *((LPDWORD) pOutputData) = 45;
635 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_WindowsW, &hroot);
636 if (res == ERROR_SUCCESS) {
637 needed = sizeof(buffer) - sizeof(WCHAR);
638 res = RegQueryValueExW(hroot, L"TransmissionRetryTimeout", NULL, NULL, (BYTE*)buffer, &needed);
639 if ((res == ERROR_SUCCESS) && (buffer[0])) {
640 *((LPDWORD) pOutputData) = wcstoul(buffer, NULL, 0);
642 RegCloseKey(hroot);
644 return ERROR_SUCCESS;
646 return ERROR_INSUFFICIENT_BUFFER;
650 if (!lstrcmpW(pszDataName, L"MonitorUI")) {
651 * pcbOutputNeeded = sizeof(L"localui.dll");
652 if (cbOutputData >= sizeof(L"localui.dll")) {
653 memcpy(pOutputData, L"localui.dll", sizeof(L"localui.dll"));
654 return ERROR_SUCCESS;
656 return ERROR_INSUFFICIENT_BUFFER;
659 if (!lstrcmpW(pszDataName, L"PortIsValid")) {
660 TRACE("InputData (%ld): %s\n", cbInputData, debugstr_w( (LPWSTR) pInputData));
661 res = get_type_from_name((LPCWSTR) pInputData);
662 TRACE("detected as %lu\n", res);
663 /* names, that we have recognized, are valid */
664 if (res) return ERROR_SUCCESS;
666 /* ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND or something else */
667 TRACE("=> %lu\n", GetLastError());
668 return GetLastError();
671 if (!lstrcmpW(pszDataName, L"SetDefaultCommConfig")) {
672 /* get the portname from the Handle */
673 ptr = wcschr(((xcv_t *)hXcv)->nameW, ' ');
674 if (ptr) {
675 ptr++; /* skip the space */
677 else
679 ptr = ((xcv_t *)hXcv)->nameW;
681 lstrcpynW(buffer, ptr, ARRAY_SIZE(buffer));
682 if (buffer[0]) buffer[lstrlenW(buffer)-1] = '\0'; /* remove the ':' */
683 res = SetDefaultCommConfigW(buffer, (LPCOMMCONFIG) pInputData, cbInputData);
684 TRACE("got %lu with %lu\n", res, GetLastError() );
685 return res ? ERROR_SUCCESS : GetLastError();
688 FIXME("command not supported: %s\n", debugstr_w(pszDataName));
689 return ERROR_INVALID_PARAMETER;
692 /*****************************************************
693 * localmon_XcvOpenPort [exported through MONITOREX]
695 * Open a Communication-Channel
697 * PARAMS
698 * pName [i] Name of selected Object
699 * GrantedAccess [i] Access-Rights to use
700 * phXcv [o] The resulting Handle is stored here
702 * RETURNS
703 * Success: TRUE
704 * Failure: FALSE
707 static BOOL WINAPI localmon_XcvOpenPort(LPCWSTR pName, ACCESS_MASK GrantedAccess, PHANDLE phXcv)
709 xcv_t * xcv;
711 TRACE("%s, 0x%lx, %p)\n", debugstr_w(pName), GrantedAccess, phXcv);
712 /* No checks for any field is done in Windows */
713 xcv = heap_alloc(FIELD_OFFSET(xcv_t, nameW[lstrlenW(pName) + 1]));
714 if (xcv) {
715 xcv->GrantedAccess = GrantedAccess;
716 lstrcpyW(xcv->nameW, pName);
717 *phXcv = xcv;
718 EnterCriticalSection(&xcv_handles_cs);
719 list_add_tail(&xcv_handles, &xcv->entry);
720 LeaveCriticalSection(&xcv_handles_cs);
721 TRACE("=> %p\n", xcv);
722 return TRUE;
724 else
726 *phXcv = NULL;
727 return FALSE;
731 /*****************************************************
732 * InitializePrintMonitor (LOCALSPL.@)
734 * Initialize the Monitor for the Local Ports
736 * PARAMS
737 * regroot [I] Registry-Path, where the settings are stored
739 * RETURNS
740 * Success: Pointer to a MONITOREX Structure
741 * Failure: NULL
743 * NOTES
744 * The fixed location "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports"
745 * is used to store the Ports (IniFileMapping from "win.ini", Section "Ports").
746 * Native localspl.dll fails, when no valid Port-Entry is present.
750 LPMONITOREX WINAPI InitializePrintMonitor(LPWSTR regroot)
752 static MONITOREX mymonitorex =
754 sizeof(MONITOR),
756 localmon_EnumPortsW,
757 localmon_OpenPortW,
758 NULL, /* localmon_OpenPortExW */
759 NULL, /* localmon_StartDocPortW */
760 NULL, /* localmon_WritePortW */
761 NULL, /* localmon_ReadPortW */
762 NULL, /* localmon_EndDocPortW */
763 localmon_ClosePort,
764 NULL, /* Use AddPortUI in localui.dll */
765 localmon_AddPortExW,
766 NULL, /* Use ConfigurePortUI in localui.dll */
767 NULL, /* Use DeletePortUI in localui.dll */
768 NULL, /* localmon_GetPrinterDataFromPort */
769 NULL, /* localmon_SetPortTimeOuts */
770 localmon_XcvOpenPort,
771 localmon_XcvDataPort,
772 localmon_XcvClosePort
776 TRACE("(%s)\n", debugstr_w(regroot));
777 /* Parameter "regroot" is ignored on NT4.0 (localmon.dll) */
778 if (!regroot || !regroot[0]) {
779 SetLastError(ERROR_INVALID_PARAMETER);
780 return NULL;
782 TRACE("=> %p\n", &mymonitorex);
783 /* Native windows returns always the same pointer on success */
784 return &mymonitorex;