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
32 #include "ddk/winsplp.h"
33 #include "localspl_private.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
42 /*****************************************************/
44 static CRITICAL_SECTION port_handles_cs
;
45 static CRITICAL_SECTION_DEBUG port_handles_cs_debug
=
47 0, 0, &port_handles_cs
,
48 { &port_handles_cs_debug
.ProcessLocksList
, &port_handles_cs_debug
.ProcessLocksList
},
49 0, 0, { (DWORD_PTR
)(__FILE__
": port_handles_cs") }
51 static CRITICAL_SECTION port_handles_cs
= { &port_handles_cs_debug
, -1, 0, 0, 0, 0 };
54 static CRITICAL_SECTION xcv_handles_cs
;
55 static CRITICAL_SECTION_DEBUG xcv_handles_cs_debug
=
57 0, 0, &xcv_handles_cs
,
58 { &xcv_handles_cs_debug
.ProcessLocksList
, &xcv_handles_cs_debug
.ProcessLocksList
},
59 0, 0, { (DWORD_PTR
)(__FILE__
": xcv_handles_cs") }
61 static CRITICAL_SECTION xcv_handles_cs
= { &xcv_handles_cs_debug
, -1, 0, 0, 0, 0 };
63 /* ############################### */
73 ACCESS_MASK GrantedAccess
;
77 static struct list port_handles
= LIST_INIT( port_handles
);
78 static struct list xcv_handles
= LIST_INIT( xcv_handles
);
80 /* ############################### */
82 static const WCHAR cmd_AddPortW
[] = {'A','d','d','P','o','r','t',0};
83 static const WCHAR cmd_DeletePortW
[] = {'D','e','l','e','t','e','P','o','r','t',0};
84 static const WCHAR cmd_ConfigureLPTPortCommandOKW
[] = {'C','o','n','f','i','g','u','r','e',
85 'L','P','T','P','o','r','t',
86 'C','o','m','m','a','n','d','O','K',0};
88 static const WCHAR cmd_GetDefaultCommConfigW
[] = {'G','e','t',
89 'D','e','f','a','u','l','t',
90 'C','o','m','m','C','o','n','f','i','g',0};
92 static const WCHAR cmd_GetTransmissionRetryTimeoutW
[] = {'G','e','t',
93 'T','r','a','n','s','m','i','s','s','i','o','n',
94 'R','e','t','r','y','T','i','m','e','o','u','t',0};
96 static const WCHAR cmd_MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
97 static const WCHAR cmd_PortIsValidW
[] = {'P','o','r','t','I','s','V','a','l','i','d',0};
98 static const WCHAR cmd_SetDefaultCommConfigW
[] = {'S','e','t',
99 'D','e','f','a','u','l','t',
100 'C','o','m','m','C','o','n','f','i','g',0};
102 static const WCHAR dllnameuiW
[] = {'l','o','c','a','l','u','i','.','d','l','l',0};
103 static const WCHAR emptyW
[] = {0};
104 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
106 static const WCHAR portname_LPT
[] = {'L','P','T',0};
107 static const WCHAR portname_COM
[] = {'C','O','M',0};
108 static const WCHAR portname_FILE
[] = {'F','I','L','E',':',0};
109 static const WCHAR portname_CUPS
[] = {'C','U','P','S',':',0};
110 static const WCHAR portname_LPR
[] = {'L','P','R',':',0};
112 static const WCHAR TransmissionRetryTimeoutW
[] = {'T','r','a','n','s','m','i','s','s','i','o','n',
113 'R','e','t','r','y','T','i','m','e','o','u','t',0};
115 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
116 'M','i','c','r','o','s','o','f','t','\\',
117 'W','i','n','d','o','w','s',' ','N','T','\\',
118 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
119 'P','o','r','t','s',0};
121 static const WCHAR WinNT_CV_WindowsW
[] = {'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s',' ','N','T','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'W','i','n','d','o','w','s',0};
128 /******************************************************************
129 * does_port_exist (internal)
131 * returns TRUE, when the Port already exists
134 static BOOL
does_port_exist(LPCWSTR myname
)
142 TRACE("(%s)\n", debugstr_w(myname
));
144 id
= EnumPortsW(NULL
, 1, NULL
, 0, &needed
, &returned
);
145 pi
= heap_alloc(needed
);
148 id
= EnumPortsW(NULL
, 1, (LPBYTE
) pi
, needed
, &needed
, &returned
);
150 if (id
&& returned
> 0) {
151 /* we got a number of valid names. */
152 for (id
= 0; id
< returned
; id
++)
154 if (lstrcmpiW(myname
, pi
[id
].pName
) == 0) {
155 TRACE("(%u) found %s\n", id
, debugstr_w(pi
[id
].pName
));
166 /******************************************************************
167 * enumerate the local Ports from the Registry (internal)
169 * See localmon_EnumPortsW.
172 * returns the needed size (in bytes) for pPorts
173 * and *lpreturned is set to number of entries returned in pPorts
177 static DWORD
get_ports_from_reg(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
182 WCHAR portname
[MAX_PATH
];
183 WCHAR res_PortW
[IDS_LOCALPORT_MAXLEN
];
184 WCHAR res_MonitorW
[IDS_LOCALMONITOR_MAXLEN
];
194 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
196 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
198 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
199 needed
= entrysize
* numentries
;
200 ptr
= (LPWSTR
) &pPorts
[needed
];
202 if (needed
> cbBuf
) pPorts
= NULL
; /* No buffer for the structs */
207 /* we do not check more parameters as done in windows */
208 if ((level
< 1) || (level
> 2)) {
209 goto getports_cleanup
;
213 reslen_MonitorW
= LoadStringW(LOCALSPL_hInstance
, IDS_LOCALMONITOR
, res_MonitorW
, IDS_LOCALMONITOR_MAXLEN
) + 1;
214 reslen_PortW
= LoadStringW(LOCALSPL_hInstance
, IDS_LOCALPORT
, res_PortW
, IDS_LOCALPORT_MAXLEN
) + 1;
216 res
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
);
217 if (res
== ERROR_SUCCESS
) {
219 /* Scan all Port-Names */
220 while (res
== ERROR_SUCCESS
) {
223 res
= RegEnumValueW(hroot
, id
, portname
, &len
, NULL
, NULL
, NULL
, NULL
);
225 if ((res
== ERROR_SUCCESS
) && (portname
[0])) {
227 /* calculate the required size */
229 needed
+= (len
+ 1) * sizeof(WCHAR
);
231 needed
+= (reslen_MonitorW
+ reslen_PortW
) * sizeof(WCHAR
);
234 /* Now fill the user-buffer, if available */
235 if (pPorts
&& (cbBuf
>= needed
)){
236 out
= (LPPORT_INFO_2W
) pPorts
;
238 TRACE("%p: writing PORT_INFO_%dW #%d (%s)\n", out
, level
, numentries
, debugstr_w(portname
));
239 out
->pPortName
= ptr
;
240 lstrcpyW(ptr
, portname
); /* Name of the Port */
243 out
->pMonitorName
= ptr
;
244 lstrcpyW(ptr
, res_MonitorW
); /* Name of the Monitor */
245 ptr
+= reslen_MonitorW
;
247 out
->pDescription
= ptr
;
248 lstrcpyW(ptr
, res_PortW
); /* Port Description */
251 out
->fPortType
= PORT_TYPE_WRITE
;
262 ERR("failed with %d for %s\n", res
, debugstr_w(WinNT_CV_PortsW
));
267 *lpreturned
= numentries
;
268 TRACE("need %d byte for %d entries (%d)\n", needed
, numentries
, GetLastError());
272 /*****************************************************
273 * get_type_from_name (internal)
277 static DWORD
get_type_from_name(LPCWSTR name
)
281 if (!strncmpW(name
, portname_LPT
, sizeof(portname_LPT
) / sizeof(WCHAR
) -1))
284 if (!strncmpW(name
, portname_COM
, sizeof(portname_COM
) / sizeof(WCHAR
) -1))
287 if (!strcmpW(name
, portname_FILE
))
291 return PORT_IS_UNIXNAME
;
296 if (!strncmpW(name
, portname_CUPS
, sizeof(portname_CUPS
) / sizeof(WCHAR
) -1))
299 if (!strncmpW(name
, portname_LPR
, sizeof(portname_LPR
) / sizeof(WCHAR
) -1))
302 /* Must be a file or a directory. Does the file exist ? */
303 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
304 TRACE("%p for OPEN_EXISTING on %s\n", hfile
, debugstr_w(name
));
305 if (hfile
== INVALID_HANDLE_VALUE
) {
306 /* Can we create the file? */
307 hfile
= CreateFileW(name
, GENERIC_WRITE
, 0, NULL
, OPEN_ALWAYS
, FILE_FLAG_DELETE_ON_CLOSE
, NULL
);
308 TRACE("%p for OPEN_ALWAYS\n", hfile
);
310 if (hfile
!= INVALID_HANDLE_VALUE
) {
312 return PORT_IS_FILENAME
;
314 /* We can't use the name. use GetLastError() for the reason */
315 return PORT_IS_UNKNOWN
;
318 /*****************************************************
319 * get_type_from_local_name (internal)
323 static DWORD
get_type_from_local_name(LPCWSTR nameW
)
326 LPWSTR myname
= NULL
;
328 DWORD numentries
= 0;
331 TRACE("(%s)\n", debugstr_w(myname
));
333 needed
= get_ports_from_reg(1, NULL
, 0, &numentries
);
334 pi
= heap_alloc(needed
);
336 needed
= get_ports_from_reg(1, (LPBYTE
) pi
, needed
, &numentries
);
338 if (pi
&& needed
&& numentries
> 0) {
339 /* we got a number of valid ports. */
341 while ((myname
== NULL
) && (id
< numentries
))
343 if (lstrcmpiW(nameW
, pi
[id
].pName
) == 0) {
344 TRACE("(%u) found %s\n", id
, debugstr_w(pi
[id
].pName
));
345 myname
= pi
[id
].pName
;
351 id
= (myname
) ? get_type_from_name(myname
) : PORT_IS_UNKNOWN
;
357 /******************************************************************************
358 * localmon_AddPortExW [exported through MONITOREX]
360 * Add a Port, without presenting a user interface
363 * pName [I] Servername or NULL (local Computer)
364 * level [I] Structure-Level (1) for pBuffer
365 * pBuffer [I] PTR to the Input-Data (PORT_INFO_1)
366 * pMonitorName [I] Name of the Monitor that manage the Port
373 * Level 2 is documented on MSDN for Portmonitors, but not supported by the
374 * "Local Port" Portmonitor (localspl.dll / localmon.dll)
376 static BOOL WINAPI
localmon_AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
382 pi
= (PORT_INFO_1W
*) pBuffer
;
383 TRACE("(%s, %d, %p, %s) => %s\n", debugstr_w(pName
), level
, pBuffer
,
384 debugstr_w(pMonitorName
), debugstr_w(pi
? pi
->pName
: NULL
));
387 if ((pMonitorName
== NULL
) || (lstrcmpiW(pMonitorName
, LocalPortW
) != 0 ) ||
388 (pi
== NULL
) || (pi
->pName
== NULL
) || (pi
->pName
[0] == '\0') ) {
389 SetLastError(ERROR_INVALID_PARAMETER
);
394 SetLastError(ERROR_INVALID_LEVEL
);
398 res
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
);
399 if (res
== ERROR_SUCCESS
) {
400 if (does_port_exist(pi
->pName
)) {
402 TRACE("=> FALSE with %u\n", ERROR_INVALID_PARAMETER
);
403 SetLastError(ERROR_INVALID_PARAMETER
);
406 res
= RegSetValueExW(hroot
, pi
->pName
, 0, REG_SZ
, (const BYTE
*) emptyW
, sizeof(emptyW
));
409 if (res
!= ERROR_SUCCESS
) SetLastError(ERROR_INVALID_PARAMETER
);
410 TRACE("=> %u with %u\n", (res
== ERROR_SUCCESS
), GetLastError());
411 return (res
== ERROR_SUCCESS
);
414 /*****************************************************
415 * localmon_ClosePort [exported through MONITOREX]
420 * hPort [i] The Handle to close
427 static BOOL WINAPI
localmon_ClosePort(HANDLE hPort
)
429 port_t
* port
= hPort
;
431 TRACE("(%p)\n", port
);
432 EnterCriticalSection(&port_handles_cs
);
433 list_remove(&port
->entry
);
434 LeaveCriticalSection(&port_handles_cs
);
439 /*****************************************************
440 * localmon_EnumPortsW [exported through MONITOREX]
442 * Enumerate all local Ports
445 * pName [I] Servername (ignored)
446 * level [I] Structure-Level (1 or 2)
447 * pPorts [O] PTR to Buffer that receives the Result
448 * cbBuf [I] Size of Buffer at pPorts
449 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
450 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
454 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
457 *| Windows ignores pName
458 *| Windows crash the app, when pPorts, pcbNeeded or pcReturned are NULL
459 *| Windows >NT4.0 does not check for illegal levels (TRUE is returned)
462 * "HCU\Software\Wine\Spooler\<portname>" - redirection
465 static BOOL WINAPI
localmon_EnumPortsW(LPWSTR pName
, DWORD level
, LPBYTE pPorts
,
466 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
472 TRACE("(%s, %d, %p, %d, %p, %p)\n",
473 debugstr_w(pName
), level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
476 needed
= get_ports_from_reg(level
, NULL
, 0, &numentries
);
477 /* we calculated the needed buffersize. now do the error-checks */
478 if (cbBuf
< needed
) {
479 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
483 /* fill the buffer with the Port-Names */
484 needed
= get_ports_from_reg(level
, pPorts
, cbBuf
, &numentries
);
487 if (pcReturned
) *pcReturned
= numentries
;
490 if (pcbNeeded
) *pcbNeeded
= needed
;
492 TRACE("returning %d with %d (%d byte for %d entries)\n",
493 res
, GetLastError(), needed
, numentries
);
498 /*****************************************************
499 * localmon_OpenPort [exported through MONITOREX]
501 * Open a Data-Channel for a Port
504 * pName [i] Name of selected Object
505 * phPort [o] The resulting Handle is stored here
512 static BOOL WINAPI
localmon_OpenPortW(LPWSTR pName
, PHANDLE phPort
)
517 TRACE("%s, %p)\n", debugstr_w(pName
), phPort
);
519 /* an empty name is invalid */
520 if (!pName
[0]) return FALSE
;
522 /* does the port exist? */
523 type
= get_type_from_local_name(pName
);
524 if (!type
) return FALSE
;
526 port
= heap_alloc(FIELD_OFFSET(port_t
, nameW
[lstrlenW(pName
) + 1]));
527 if (!port
) return FALSE
;
530 lstrcpyW(port
->nameW
, pName
);
533 EnterCriticalSection(&port_handles_cs
);
534 list_add_tail(&port_handles
, &port
->entry
);
535 LeaveCriticalSection(&port_handles_cs
);
537 TRACE("=> %p\n", port
);
541 /*****************************************************
542 * localmon_XcvClosePort [exported through MONITOREX]
544 * Close a Communication-Channel
547 * hXcv [i] The Handle to close
554 static BOOL WINAPI
localmon_XcvClosePort(HANDLE hXcv
)
558 TRACE("(%p)\n", xcv
);
559 /* No checks are done in Windows */
560 EnterCriticalSection(&xcv_handles_cs
);
561 list_remove(&xcv
->entry
);
562 LeaveCriticalSection(&xcv_handles_cs
);
567 /*****************************************************
568 * localmon_XcvDataPort [exported through MONITOREX]
570 * Execute command through a Communication-Channel
573 * hXcv [i] The Handle to work with
574 * pszDataName [i] Name of the command to execute
575 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
576 * cbInputData [i] Size in Bytes of Buffer at pInputData
577 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
578 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
579 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
582 * Success: ERROR_SUCCESS
583 * Failure: win32 error code
587 * Minimal List of commands, that every Printmonitor DLL should support:
589 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
590 *| "AddPort" : Add a Port (Name as WSTR in pInputData)
591 *| "DeletePort": Delete a Port (Name as WSTR in pInputData)
595 static DWORD WINAPI
localmon_XcvDataPort(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
, DWORD cbInputData
,
596 PBYTE pOutputData
, DWORD cbOutputData
, PDWORD pcbOutputNeeded
)
598 WCHAR buffer
[16]; /* buffer for a decimal number */
604 TRACE("(%p, %s, %p, %d, %p, %d, %p)\n", hXcv
, debugstr_w(pszDataName
),
605 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
607 if (!lstrcmpW(pszDataName
, cmd_AddPortW
)) {
608 TRACE("InputData (%d): %s\n", cbInputData
, debugstr_w( (LPWSTR
) pInputData
));
609 res
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
);
610 if (res
== ERROR_SUCCESS
) {
611 if (does_port_exist((LPWSTR
) pInputData
)) {
613 TRACE("=> %u\n", ERROR_ALREADY_EXISTS
);
614 return ERROR_ALREADY_EXISTS
;
616 res
= RegSetValueExW(hroot
, (LPWSTR
) pInputData
, 0, REG_SZ
, (const BYTE
*) emptyW
, sizeof(emptyW
));
619 TRACE("=> %u\n", res
);
624 if (!lstrcmpW(pszDataName
, cmd_ConfigureLPTPortCommandOKW
)) {
625 TRACE("InputData (%d): %s\n", cbInputData
, debugstr_w( (LPWSTR
) pInputData
));
626 res
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_WindowsW
, &hroot
);
627 if (res
== ERROR_SUCCESS
) {
628 res
= RegSetValueExW(hroot
, TransmissionRetryTimeoutW
, 0, REG_SZ
, pInputData
, cbInputData
);
634 if (!lstrcmpW(pszDataName
, cmd_DeletePortW
)) {
635 TRACE("InputData (%d): %s\n", cbInputData
, debugstr_w( (LPWSTR
) pInputData
));
636 res
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
);
637 if (res
== ERROR_SUCCESS
) {
638 res
= RegDeleteValueW(hroot
, (LPWSTR
) pInputData
);
640 TRACE("=> %u with %u\n", res
, GetLastError() );
643 return ERROR_FILE_NOT_FOUND
;
646 if (!lstrcmpW(pszDataName
, cmd_GetDefaultCommConfigW
)) {
647 TRACE("InputData (%d): %s\n", cbInputData
, debugstr_w( (LPWSTR
) pInputData
));
648 *pcbOutputNeeded
= cbOutputData
;
649 res
= GetDefaultCommConfigW((LPWSTR
) pInputData
, (LPCOMMCONFIG
) pOutputData
, pcbOutputNeeded
);
650 TRACE("got %u with %u\n", res
, GetLastError() );
651 return res
? ERROR_SUCCESS
: GetLastError();
654 if (!lstrcmpW(pszDataName
, cmd_GetTransmissionRetryTimeoutW
)) {
655 * pcbOutputNeeded
= sizeof(DWORD
);
656 if (cbOutputData
>= sizeof(DWORD
)) {
657 /* the w2k resource kit documented a default of 90, but that's wrong */
658 *((LPDWORD
) pOutputData
) = 45;
660 res
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_WindowsW
, &hroot
);
661 if (res
== ERROR_SUCCESS
) {
662 needed
= sizeof(buffer
) - sizeof(WCHAR
);
663 res
= RegQueryValueExW(hroot
, TransmissionRetryTimeoutW
, NULL
, NULL
, (LPBYTE
) buffer
, &needed
);
664 if ((res
== ERROR_SUCCESS
) && (buffer
[0])) {
665 *((LPDWORD
) pOutputData
) = strtoulW(buffer
, NULL
, 0);
669 return ERROR_SUCCESS
;
671 return ERROR_INSUFFICIENT_BUFFER
;
675 if (!lstrcmpW(pszDataName
, cmd_MonitorUIW
)) {
676 * pcbOutputNeeded
= sizeof(dllnameuiW
);
677 if (cbOutputData
>= sizeof(dllnameuiW
)) {
678 memcpy(pOutputData
, dllnameuiW
, sizeof(dllnameuiW
));
679 return ERROR_SUCCESS
;
681 return ERROR_INSUFFICIENT_BUFFER
;
684 if (!lstrcmpW(pszDataName
, cmd_PortIsValidW
)) {
685 TRACE("InputData (%d): %s\n", cbInputData
, debugstr_w( (LPWSTR
) pInputData
));
686 res
= get_type_from_name((LPCWSTR
) pInputData
);
687 TRACE("detected as %u\n", res
);
688 /* names, that we have recognized, are valid */
689 if (res
) return ERROR_SUCCESS
;
691 /* ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND or something else */
692 TRACE("=> %u\n", GetLastError());
693 return GetLastError();
696 if (!lstrcmpW(pszDataName
, cmd_SetDefaultCommConfigW
)) {
697 /* get the portname from the Handle */
698 ptr
= strchrW(((xcv_t
*)hXcv
)->nameW
, ' ');
700 ptr
++; /* skip the space */
704 ptr
= ((xcv_t
*)hXcv
)->nameW
;
706 lstrcpynW(buffer
, ptr
, sizeof(buffer
)/sizeof(WCHAR
));
707 if (buffer
[0]) buffer
[lstrlenW(buffer
)-1] = '\0'; /* remove the ':' */
708 res
= SetDefaultCommConfigW(buffer
, (LPCOMMCONFIG
) pInputData
, cbInputData
);
709 TRACE("got %u with %u\n", res
, GetLastError() );
710 return res
? ERROR_SUCCESS
: GetLastError();
713 FIXME("command not supported: %s\n", debugstr_w(pszDataName
));
714 return ERROR_INVALID_PARAMETER
;
717 /*****************************************************
718 * localmon_XcvOpenPort [exported through MONITOREX]
720 * Open a Communication-Channel
723 * pName [i] Name of selected Object
724 * GrantedAccess [i] Access-Rights to use
725 * phXcv [o] The resulting Handle is stored here
732 static BOOL WINAPI
localmon_XcvOpenPort(LPCWSTR pName
, ACCESS_MASK GrantedAccess
, PHANDLE phXcv
)
736 TRACE("%s, 0x%x, %p)\n", debugstr_w(pName
), GrantedAccess
, phXcv
);
737 /* No checks for any field is done in Windows */
738 xcv
= heap_alloc(FIELD_OFFSET(xcv_t
, nameW
[lstrlenW(pName
) + 1]));
740 xcv
->GrantedAccess
= GrantedAccess
;
741 lstrcpyW(xcv
->nameW
, pName
);
743 EnterCriticalSection(&xcv_handles_cs
);
744 list_add_tail(&xcv_handles
, &xcv
->entry
);
745 LeaveCriticalSection(&xcv_handles_cs
);
746 TRACE("=> %p\n", xcv
);
756 /*****************************************************
757 * InitializePrintMonitor (LOCALSPL.@)
759 * Initialize the Monitor for the Local Ports
762 * regroot [I] Registry-Path, where the settings are stored
765 * Success: Pointer to a MONITOREX Structure
769 * The fixed location "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports"
770 * is used to store the Ports (IniFileMapping from "win.ini", Section "Ports").
771 * Native localspl.dll fails, when no valid Port-Entry is present.
775 LPMONITOREX WINAPI
InitializePrintMonitor(LPWSTR regroot
)
777 static MONITOREX mymonitorex
=
779 sizeof(MONITOREX
) - sizeof(DWORD
),
783 NULL
, /* localmon_OpenPortExW */
784 NULL
, /* localmon_StartDocPortW */
785 NULL
, /* localmon_WritePortW */
786 NULL
, /* localmon_ReadPortW */
787 NULL
, /* localmon_EndDocPortW */
789 NULL
, /* Use AddPortUI in localui.dll */
791 NULL
, /* Use ConfigurePortUI in localui.dll */
792 NULL
, /* Use DeletePortUI in localui.dll */
793 NULL
, /* localmon_GetPrinterDataFromPort */
794 NULL
, /* localmon_SetPortTimeOuts */
795 localmon_XcvOpenPort
,
796 localmon_XcvDataPort
,
797 localmon_XcvClosePort
801 TRACE("(%s)\n", debugstr_w(regroot
));
802 /* Parameter "regroot" is ignored on NT4.0 (localmon.dll) */
803 if (!regroot
|| !regroot
[0]) {
804 SetLastError(ERROR_INVALID_PARAMETER
);
807 TRACE("=> %p\n", &mymonitorex
);
808 /* Native windows returns always the same pointer on success */