ReactOS 0.4.15-dev-8096-ga0eec98
ports.c File Reference
#include "precomp.h"
Include dependency graph for ports.c:

Go to the source code of this file.

Functions

_GetNonspooledPortName

Prepends "NONSPOOLED_" to a port name without colon.

Parameters
pwszPortNameWithoutColonResult of a previous GetPortNameWithoutColon call.
ppwszNonspooledPortNamePointer to a buffer that will contain the NONSPOOLED port name. You have to free this buffer using DllFreeSplMem.
Returns
ERROR_SUCCESS if the NONSPOOLED port name was successfully copied into the buffer. ERROR_NOT_ENOUGH_MEMORY if memory allocation failed.
static __inline DWORD _GetNonspooledPortName (PCWSTR pwszPortNameWithoutColon, PWSTR *ppwszNonspooledPortName)
 
_IsLegacyPort

Checks if the given port name is a legacy port (COM or LPT). This check is extra picky to not cause false positives (like file name ports starting with "COM" or "LPT").

Parameters
pwszPortNameThe port name to check.
pwszPortTypeL"COM" or L"LPT"
Returns
TRUE if this is definitely the asked legacy port, FALSE if not.
static __inline BOOL _IsLegacyPort (PCWSTR pwszPortName, PCWSTR pwszPortType)
 
_ClosePortHandles

Closes a port of any type if it's open. Removes any saved mapping or existing definition of a NONSPOOLED device mapping.

Parameters
pPortThe port you want to close.
static void _ClosePortHandles (PLOCALMON_PORT pPort)
 
_CreateNonspooledPort

Queries the system-wide device definition of the given port. If such a definition exists, it's a legacy port remapped to a named pipe by the spooler. In this case, the function creates and opens a NONSPOOLED device definition to the most recent mapping before the current one (usually the physical device).

Parameters
pPortPointer to the LOCALMON_PORT structure of the desired port.
Returns
TRUE if a NONSPOOLED port was successfully created, FALSE otherwise. A more specific error code can be obtained through GetLastError. In particular, if the return value is FALSE and GetLastError returns ERROR_SUCCESS, no NONSPOOLED port is needed for this port.
static BOOL _CreateNonspooledPort (PLOCALMON_PORT pPort)
 
static PLOCALMON_PORT _FindPort (PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
 
static void _LocalmonGetPortLevel1 (PLOCALMON_PORT pPort, PPORT_INFO_1W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
 
static void _LocalmonGetPortLevel2 (PLOCALMON_PORT pPort, PPORT_INFO_2W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
 
_SetTransmissionRetryTimeout

Checks if the given port is a physical one and sets the transmission retry timeout in this case using the value from registry.

Parameters
pPortThe port to operate on.
Returns
TRUE if the given port is a physical one, FALSE otherwise.
static BOOL _SetTransmissionRetryTimeout (PLOCALMON_PORT pPort)
 
BOOL WINAPI LocalmonClosePort (HANDLE hPort)
 
BOOL WINAPI LocalmonEndDocPort (HANDLE hPort)
 
BOOL WINAPI LocalmonEnumPorts (HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 
BOOL WINAPI LocalmonGetPrinterDataFromPort (HANDLE hPort, DWORD ControlID, PWSTR pValueName, PWSTR lpInBuffer, DWORD cbInBuffer, PWSTR lpOutBuffer, DWORD cbOutBuffer, PDWORD lpcbReturned)
 
BOOL WINAPI LocalmonOpenPort (HANDLE hMonitor, PWSTR pName, PHANDLE pHandle)
 
BOOL WINAPI LocalmonSetPortTimeOuts (HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD Reserved)
 
BOOL WINAPI LocalmonReadPort (HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead)
 
BOOL WINAPI LocalmonStartDocPort (HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo)
 
BOOL WINAPI LocalmonWritePort (HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten)
 
BOOL WINAPI LocalmonAddPortEx (HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
 
BOOL WINAPI LocalmonAddPort (HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
 
BOOL WINAPI LocalmonConfigurePort (HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName)
 
BOOL WINAPI LocalmonDeletePort (HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName)
 

Variables

static const WCHAR wszNonspooledPrefix [] = L"NONSPOOLED_"
 
static const DWORD cchNonspooledPrefix = _countof(wszNonspooledPrefix) - 1
 
static DWORD dwPortInfo1Offsets []
 
static DWORD dwPortInfo2Offsets []
 

Function Documentation

◆ _ClosePortHandles()

static void _ClosePortHandles ( PLOCALMON_PORT  pPort)
static

Definition at line 113 of file ports.c.

114{
115 PWSTR pwszNonspooledPortName;
116 PWSTR pwszPortNameWithoutColon;
117
118 // A port is already fully closed if the file handle is invalid.
119 if (pPort->hFile == INVALID_HANDLE_VALUE)
120 return;
121
122 // Close the file handle.
123 CloseHandle(pPort->hFile);
125
126 // A NONSPOOLED port was only created if pwszMapping contains the current port mapping.
127 if (!pPort->pwszMapping)
128 return;
129
130 // Free the information about the current mapping.
132 pPort->pwszMapping = NULL;
133
134 // Finally get the required strings and remove the DOS device definition for the NONSPOOLED port.
135 if (GetPortNameWithoutColon(pPort->pwszPortName, &pwszPortNameWithoutColon) == ERROR_SUCCESS)
136 {
137 if (_GetNonspooledPortName(pwszPortNameWithoutColon, &pwszNonspooledPortName) == ERROR_SUCCESS)
138 {
139 DefineDosDeviceW(DDD_REMOVE_DEFINITION, pwszNonspooledPortName, NULL);
140 DllFreeSplMem(pwszNonspooledPortName);
141 }
142 DllFreeSplMem(pwszPortNameWithoutColon);
143 }
144}
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
BOOL WINAPI DefineDosDeviceW(DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath)
Definition: dosdev.c:232
PWSTR pwszPortName
Definition: precomp.h:55
PWSTR pwszMapping
Definition: precomp.h:69
HANDLE hFile
Definition: precomp.h:67
uint16_t * PWSTR
Definition: typedefs.h:56
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
BOOL WINAPI DllFreeSplStr(PWSTR pwszString)
Definition: memory.c:130
static __inline DWORD _GetNonspooledPortName(PCWSTR pwszPortNameWithoutColon, PWSTR *ppwszNonspooledPortName)
Definition: ports.c:44
DWORD GetPortNameWithoutColon(PCWSTR pwszPortName, PWSTR *ppwszPortNameWithoutColon)
Definition: tools.c:142
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:524

Referenced by LocalmonClosePort(), LocalmonEndDocPort(), LocalmonGetPrinterDataFromPort(), LocalmonOpenPort(), LocalmonReadPort(), LocalmonSetPortTimeOuts(), and LocalmonWritePort().

◆ _CreateNonspooledPort()

static BOOL _CreateNonspooledPort ( PLOCALMON_PORT  pPort)
static

Definition at line 162 of file ports.c.

163{
164 const WCHAR wszLocalSlashes[] = L"\\\\.\\";
165 const DWORD cchLocalSlashes = _countof(wszLocalSlashes) - 1;
166
167 const WCHAR wszSpoolerNamedPipe[] = L"\\Device\\NamedPipe\\Spooler\\";
168 const DWORD cchSpoolerNamedPipe = _countof(wszSpoolerNamedPipe) - 1;
169
170 BOOL bReturnValue = FALSE;
171 DWORD cchPortNameWithoutColon;
172 DWORD dwErrorCode;
173 HANDLE hToken = NULL;
174 PWSTR p;
175 PWSTR pwszDeviceMappings = NULL;
176 PWSTR pwszNonspooledFileName = NULL;
177 PWSTR pwszNonspooledPortName = NULL;
178 PWSTR pwszPipeName = NULL;
179 PWSTR pwszPortNameWithoutColon = NULL;
180
181 // We need the port name without the trailing colon.
182 dwErrorCode = GetPortNameWithoutColon(pPort->pwszPortName, &pwszPortNameWithoutColon);
183 if (dwErrorCode == ERROR_INVALID_PARAMETER)
184 {
185 // This port has no trailing colon, so we also need no NONSPOOLED mapping for it.
186 dwErrorCode = ERROR_SUCCESS;
187 goto Cleanup;
188 }
189 else if (dwErrorCode != ERROR_SUCCESS)
190 {
191 // Another unexpected failure.
192 goto Cleanup;
193 }
194
195 cchPortNameWithoutColon = wcslen(pwszPortNameWithoutColon);
196
197 // The spooler has usually remapped the legacy port to a named pipe of the format in wszSpoolerNamedPipe.
198 // Construct the device name of this pipe.
199 pwszPipeName = DllAllocSplMem((cchSpoolerNamedPipe + cchPortNameWithoutColon + 1) * sizeof(WCHAR));
200 if (!pwszPipeName)
201 {
202 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
203 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
204 goto Cleanup;
205 }
206
207 CopyMemory(pwszPipeName, wszSpoolerNamedPipe, cchSpoolerNamedPipe * sizeof(WCHAR));
208 CopyMemory(&pwszPipeName[cchSpoolerNamedPipe], pwszPortNameWithoutColon, (cchPortNameWithoutColon + 1) * sizeof(WCHAR));
209
210 // QueryDosDeviceW is one of the shitty APIs that gives no information about the required buffer size and wants you to know it by pure magic.
211 // Examples show that a value of MAX_PATH * sizeof(WCHAR) is usually taken here, so we have no other option either.
212 pwszDeviceMappings = DllAllocSplMem(MAX_PATH * sizeof(WCHAR));
213 if (!pwszDeviceMappings)
214 {
215 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
216 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
217 goto Cleanup;
218 }
219
220 // Switch to the SYSTEM context, because we're only interested in creating NONSPOOLED ports for system-wide ports.
221 // User-local ports (like _some_ redirected networked ones) aren't remapped by the spooler and can be opened directly.
222 hToken = RevertToPrinterSelf();
223 if (!hToken)
224 {
225 dwErrorCode = GetLastError();
226 ERR("RevertToPrinterSelf failed with error %lu!\n", dwErrorCode);
227 goto Cleanup;
228 }
229
230 // QueryDosDeviceW returns the current mapping and a list of prior mappings of this legacy port, which is managed as a DOS device in the system.
231 if (!QueryDosDeviceW(pwszPortNameWithoutColon, pwszDeviceMappings, MAX_PATH))
232 {
233 // No system-wide port exists, so we also need no NONSPOOLED mapping.
234 dwErrorCode = ERROR_SUCCESS;
235 goto Cleanup;
236 }
237
238 // Check if this port has already been opened by _CreateNonspooledPort previously.
239 if (pPort->pwszMapping)
240 {
241 // In this case, we just need to do something if the mapping has changed.
242 // Therefore, check if the stored mapping equals the current mapping.
243 if (wcscmp(pPort->pwszMapping, pwszDeviceMappings) == 0)
244 {
245 // We don't need to do anything in this case.
246 dwErrorCode = ERROR_SUCCESS;
247 goto Cleanup;
248 }
249 else
250 {
251 // Close the open file handle and free the memory for pwszMapping before remapping.
252 CloseHandle(pPort->hFile);
254
256 pPort->pwszMapping = NULL;
257 }
258 }
259
260 // The port is usually mapped to the named pipe and this is how we received our data for printing.
261 // What we now need for accessing the actual port is the most recent mapping different from the named pipe.
262 p = pwszDeviceMappings;
263
264 for (;;)
265 {
266 if (!*p)
267 {
268 // We reached the end of the list without finding a mapping.
269 ERR("Can't find a suitable mapping for the port \"%S\"!\n", pPort->pwszPortName);
270 goto Cleanup;
271 }
272
273 if (_wcsicmp(p, pwszPipeName) != 0)
274 break;
275
276 // Advance to the next mapping in the list.
277 p += wcslen(p) + 1;
278 }
279
280 // We now want to create a DOS device "NONSPOOLED_<PortName>" to this mapping, so that we're able to open it through CreateFileW.
281 dwErrorCode = _GetNonspooledPortName(pwszPortNameWithoutColon, &pwszNonspooledPortName);
282 if (dwErrorCode != ERROR_SUCCESS)
283 goto Cleanup;
284
285 // Delete a possibly existing NONSPOOLED device before creating the new one, so we don't stack up device definitions.
286 DefineDosDeviceW(DDD_REMOVE_DEFINITION, pwszNonspooledPortName, NULL);
287
288 if (!DefineDosDeviceW(DDD_RAW_TARGET_PATH, pwszNonspooledPortName, p))
289 {
290 dwErrorCode = GetLastError();
291 ERR("DefineDosDeviceW failed with error %lu!\n", dwErrorCode);
292 goto Cleanup;
293 }
294
295 // This is all we needed to do in SYSTEM context.
297 hToken = NULL;
298
299 // Construct the file name to our created device for CreateFileW.
300 pwszNonspooledFileName = DllAllocSplMem((cchLocalSlashes + cchNonspooledPrefix + cchPortNameWithoutColon + 1) * sizeof(WCHAR));
301 if (!pwszNonspooledFileName)
302 {
303 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
304 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
305 goto Cleanup;
306 }
307
308 CopyMemory(pwszNonspooledFileName, wszLocalSlashes, cchLocalSlashes * sizeof(WCHAR));
309 CopyMemory(&pwszNonspooledFileName[cchLocalSlashes], wszNonspooledPrefix, cchNonspooledPrefix * sizeof(WCHAR));
310 CopyMemory(&pwszNonspooledFileName[cchLocalSlashes + cchNonspooledPrefix], pwszPortNameWithoutColon, (cchPortNameWithoutColon + 1) * sizeof(WCHAR));
311
312 // Finally open it for reading and writing.
313 pPort->hFile = CreateFileW(pwszNonspooledFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
314 if (pPort->hFile == INVALID_HANDLE_VALUE)
315 {
316 dwErrorCode = GetLastError();
317 ERR("CreateFileW failed with error %lu!\n", dwErrorCode);
318 goto Cleanup;
319 }
320
321 // Store the current mapping of the port, so that we can check if it has changed.
322 pPort->pwszMapping = AllocSplStr(pwszDeviceMappings);
323 if (!pPort->pwszMapping)
324 {
325 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
326 goto Cleanup;
327 }
328
329 bReturnValue = TRUE;
330 dwErrorCode = ERROR_SUCCESS;
331
332Cleanup:
333 if (hToken)
335
336 if (pwszDeviceMappings)
337 DllFreeSplMem(pwszDeviceMappings);
338
339 if (pwszNonspooledFileName)
340 DllFreeSplMem(pwszNonspooledFileName);
341
342 if (pwszNonspooledPortName)
343 DllFreeSplMem(pwszNonspooledPortName);
344
345 if (pwszPipeName)
346 DllFreeSplMem(pwszPipeName);
347
348 if (pwszPortNameWithoutColon)
349 DllFreeSplMem(pwszPortNameWithoutColon);
350
351 SetLastError(dwErrorCode);
352 return bReturnValue;
353}
#define ERR(fmt,...)
Definition: debug.h:113
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define SetLastError(x)
Definition: compat.h:752
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define CreateFileW
Definition: compat.h:741
#define FILE_SHARE_READ
Definition: compat.h:136
DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax)
Definition: dosdev.c:542
static const WCHAR Cleanup[]
Definition: register.c:80
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLfloat GLfloat p
Definition: glext.h:8902
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define CREATE_ALWAYS
Definition: disk.h:72
#define GENERIC_WRITE
Definition: nt_native.h:90
#define L(x)
Definition: ntvdm.h:50
HANDLE WINAPI RevertToPrinterSelf(VOID)
Definition: context.c:64
BOOL WINAPI ImpersonatePrinterClient(_In_ HANDLE hToken)
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define _countof(array)
Definition: sndvol32.h:70
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput)
Definition: memory.c:56
static const DWORD cchNonspooledPrefix
Definition: ports.c:12
static const WCHAR wszNonspooledPrefix[]
Definition: ports.c:11
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define DDD_RAW_TARGET_PATH
Definition: winbase.h:523
#define CopyMemory
Definition: winbase.h:1710
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by LocalmonGetPrinterDataFromPort(), LocalmonOpenPort(), LocalmonReadPort(), LocalmonSetPortTimeOuts(), LocalmonStartDocPort(), and LocalmonWritePort().

◆ _FindPort()

static PLOCALMON_PORT _FindPort ( PLOCALMON_HANDLE  pLocalmon,
PCWSTR  pwszPortName 
)
static

Definition at line 356 of file ports.c.

357{
359 PLOCALMON_PORT pPort;
360
361 for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
362 {
364
365 if (wcscmp(pPort->pwszPortName, pwszPortName) == 0)
366 return pPort;
367 }
368
369 return NULL;
370}
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
base of all file and directory entries
Definition: entries.h:83
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
LIST_ENTRY RegistryPorts
Definition: precomp.h:43
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

Referenced by LocalmonDeletePort(), and LocalmonOpenPort().

◆ _GetNonspooledPortName()

static __inline DWORD _GetNonspooledPortName ( PCWSTR  pwszPortNameWithoutColon,
PWSTR ppwszNonspooledPortName 
)
static

Definition at line 44 of file ports.c.

45{
46 DWORD cchPortNameWithoutColon;
47
48 cchPortNameWithoutColon = wcslen(pwszPortNameWithoutColon);
49
50 *ppwszNonspooledPortName = DllAllocSplMem((cchNonspooledPrefix + cchPortNameWithoutColon + 1) * sizeof(WCHAR));
51 if (!*ppwszNonspooledPortName)
52 {
53 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
55 }
56
57 CopyMemory(*ppwszNonspooledPortName, wszNonspooledPrefix, cchNonspooledPrefix * sizeof(WCHAR));
58 CopyMemory(&(*ppwszNonspooledPortName)[cchNonspooledPrefix], pwszPortNameWithoutColon, (cchPortNameWithoutColon + 1) * sizeof(WCHAR));
59
60 return ERROR_SUCCESS;
61}

Referenced by _ClosePortHandles(), and _CreateNonspooledPort().

◆ _IsLegacyPort()

static __inline BOOL _IsLegacyPort ( PCWSTR  pwszPortName,
PCWSTR  pwszPortType 
)
static

Definition at line 79 of file ports.c.

80{
81 const DWORD cchPortType = 3;
82 PCWSTR p = pwszPortName;
83
84 // The port name must begin with pwszPortType.
85 if (_wcsnicmp(p, pwszPortType, cchPortType) != 0)
86 return FALSE;
87
88 p += cchPortType;
89
90 // Now an arbitrary number of digits may follow.
91 while (*p >= L'0' && *p <= L'9')
92 p++;
93
94 // Finally, the legacy port must be terminated by a colon.
95 if (*p != ':')
96 return FALSE;
97
98 // If this is the end of the string, we have a legacy port.
99 p++;
100 return (*p == L'\0');
101}
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
const uint16_t * PCWSTR
Definition: typedefs.h:57

Referenced by LocalmonOpenPort().

◆ _LocalmonGetPortLevel1()

static void _LocalmonGetPortLevel1 ( PLOCALMON_PORT  pPort,
PPORT_INFO_1W ppPortInfo,
PBYTE ppPortInfoEnd,
PDWORD  pcbNeeded 
)
static

Definition at line 373 of file ports.c.

374{
375 DWORD cbPortName;
376 PCWSTR pwszStrings[1];
377
378 // Calculate the string lengths.
379 if (!ppPortInfo)
380 {
381 cbPortName = (wcslen(pPort->pwszPortName) + 1) * sizeof(WCHAR);
382
383 *pcbNeeded += sizeof(PORT_INFO_1W) + cbPortName;
384 return;
385 }
386
387 // Set the pName field.
388 pwszStrings[0] = pPort->pwszPortName;
389
390 // Copy the structure and advance to the next one in the output buffer.
391 *ppPortInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPortInfo), dwPortInfo1Offsets, *ppPortInfoEnd);
392 (*ppPortInfo)++;
393}
PBYTE WINAPI PackStrings(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
BYTE * PBYTE
Definition: pedump.c:66
static DWORD dwPortInfo1Offsets[]
Definition: ports.c:14
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3828
struct _PORT_INFO_1W PORT_INFO_1W

Referenced by LocalmonEnumPorts().

◆ _LocalmonGetPortLevel2()

static void _LocalmonGetPortLevel2 ( PLOCALMON_PORT  pPort,
PPORT_INFO_2W ppPortInfo,
PBYTE ppPortInfoEnd,
PDWORD  pcbNeeded 
)
static

Definition at line 396 of file ports.c.

397{
398 DWORD cbPortName;
399 PCWSTR pwszStrings[3];
400
401 // Calculate the string lengths.
402 if (!ppPortInfo)
403 {
404 cbPortName = (wcslen(pPort->pwszPortName) + 1) * sizeof(WCHAR);
405
406 *pcbNeeded += sizeof(PORT_INFO_2W) + cbPortName + cbLocalMonitor + cbLocalPort;
407 return;
408 }
409
410 // All local ports are writable and readable.
411 (*ppPortInfo)->fPortType = PORT_TYPE_WRITE | PORT_TYPE_READ;
412 (*ppPortInfo)->Reserved = 0;
413
414 // Set the pPortName field.
415 pwszStrings[0] = pPort->pwszPortName;
416
417 // Set the pMonitorName field.
418 pwszStrings[1] = (PWSTR)pwszLocalMonitor;
419
420 // Set the pDescription field.
421 pwszStrings[2] = (PWSTR)pwszLocalPort;
422
423 // Copy the structure and advance to the next one in the output buffer.
424 *ppPortInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPortInfo), dwPortInfo2Offsets, *ppPortInfoEnd);
425 (*ppPortInfo)++;
426}
PCWSTR pwszLocalMonitor
Definition: main.c:13
DWORD cbLocalMonitor
Definition: main.c:11
DWORD cbLocalPort
Definition: main.c:12
PCWSTR pwszLocalPort
Definition: main.c:14
static DWORD dwPortInfo2Offsets[]
Definition: ports.c:19
#define PORT_TYPE_READ
Definition: winspool.h:777
#define PORT_TYPE_WRITE
Definition: winspool.h:776
struct _PORT_INFO_2W PORT_INFO_2W

Referenced by LocalmonEnumPorts().

◆ _SetTransmissionRetryTimeout()

static BOOL _SetTransmissionRetryTimeout ( PLOCALMON_PORT  pPort)
static

Definition at line 440 of file ports.c.

441{
442 COMMTIMEOUTS CommTimeouts;
443
444 // Get the timeout from the port.
445 if (!GetCommTimeouts(pPort->hFile, &CommTimeouts))
446 return FALSE;
447
448 // Set the timeout using the value from registry.
450 SetCommTimeouts(pPort->hFile, &CommTimeouts);
451
452 return TRUE;
453}
BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
Definition: comm.c:1062
BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
Definition: comm.c:1020
DWORD WriteTotalTimeoutConstant
Definition: winbase.h:713
DWORD GetLPTTransmissionRetryTimeout(VOID)
Definition: tools.c:85

Referenced by LocalmonOpenPort(), and LocalmonStartDocPort().

◆ LocalmonAddPort()

BOOL WINAPI LocalmonAddPort ( HANDLE  hMonitor,
LPWSTR  pName,
HWND  hWnd,
LPWSTR  pMonitorName 
)

Definition at line 1137 of file ports.c.

1138{
1139 DWORD res, cbPortName;
1140 HKEY hroot;
1141 PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
1142 PLOCALMON_PORT pPort;
1143 WCHAR PortName[MAX_PATH] = {0}; // Need to use a Dialog to get name.
1144
1145 FIXME("LocalmonAddPort : %s\n", debugstr_w( (LPWSTR) pMonitorName ) );
1146
1147 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", &hroot);
1148 if (res == ERROR_SUCCESS)
1149 {
1150 if ( DoesPortExist( PortName ) )
1151 {
1152 RegCloseKey(hroot);
1153 FIXME("=> %u\n", ERROR_ALREADY_EXISTS);
1155 goto Cleanup;
1156 }
1157
1158 cbPortName = (wcslen( PortName ) + 1) * sizeof(WCHAR);
1159
1160 // Create a new LOCALMON_PORT structure for it.
1161 pPort = DllAllocSplMem(sizeof(LOCALMON_PORT) + cbPortName);
1162 if (!pPort)
1163 {
1165 RegCloseKey( hroot );
1166 goto Cleanup;
1167 }
1168
1169 pPort->Sig = SIGLCMPORT;
1170 pPort->hFile = INVALID_HANDLE_VALUE;
1171 pPort->pLocalmon = pLocalmon;
1172 pPort->pwszPortName = wcscpy( (PWSTR)(pPort+1), PortName );
1173
1174 // Insert it into the Registry list.
1175 InsertTailList(&pLocalmon->RegistryPorts, &pPort->Entry);
1176
1177 res = RegSetValueExW(hroot, PortName, 0, REG_SZ, (const BYTE *) L"", sizeof(L""));
1178 RegCloseKey(hroot);
1179 }
1180
1181 FIXME("=> %u\n", res);
1182
1183Cleanup:
1185 return (res == ERROR_SUCCESS);
1186}
static UNICODE_STRING PortName
#define FIXME(fmt,...)
Definition: debug.h:114
#define RegCloseKey(hKey)
Definition: registry.h:49
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3268
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4882
#define InsertTailList(ListHead, Entry)
GLuint res
Definition: glext.h:9613
#define debugstr_w
Definition: kernel32.h:32
#define REG_SZ
Definition: layer.c:22
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
DWORD Sig
Definition: precomp.h:57
PLOCALMON_HANDLE pLocalmon
Definition: precomp.h:56
LIST_ENTRY Entry
Definition: precomp.h:54
#define SIGLCMPORT
Definition: precomp.h:31
struct _LOCALMON_HANDLE * PLOCALMON_HANDLE
BOOL DoesPortExist(PCWSTR pwszPortName)
Definition: tools.c:24
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
WCHAR * LPWSTR
Definition: xmlstorage.h:184
unsigned char BYTE
Definition: xxhash.c:193

◆ LocalmonAddPortEx()

BOOL WINAPI LocalmonAddPortEx ( HANDLE  hMonitor,
LPWSTR  pName,
DWORD  Level,
LPBYTE  lpBuffer,
LPWSTR  lpMonitorName 
)

Definition at line 1054 of file ports.c.

1055{
1056 PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
1057 PLOCALMON_PORT pPort;
1058 HKEY hKey;
1059 DWORD dwErrorCode, cbPortName;
1061
1062 FIXME("LocalmonAddPortEx(%p, %lu, %p, %s) => %s\n", hMonitor, Level, lpBuffer, debugstr_w(lpMonitorName), debugstr_w(pi ? pi->pName : NULL));
1063
1064 // Sanity checks
1065 if ( !pLocalmon )
1066 {
1067 dwErrorCode = ERROR_INVALID_PARAMETER;
1068 goto Cleanup;
1069 }
1070
1071 if ( ( lpMonitorName == NULL ) ||
1072 ( lstrcmpiW( lpMonitorName, L"Local Port" ) != 0 ) ||
1073 ( pi == NULL ) ||
1074 ( pi->pName == NULL ) ||
1075 ( pi->pName[0] == '\0' ) )
1076 {
1077 ERR("Fail Monitor Port Name\n");
1079 return FALSE;
1080 }
1081
1082 if ( Level != 1 )
1083 {
1085 return FALSE;
1086 }
1087
1088 dwErrorCode = RegOpenKeyW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", &hKey );
1089 if ( dwErrorCode == ERROR_SUCCESS )
1090 {
1091 if ( DoesPortExist( pi->pName ) )
1092 {
1093 RegCloseKey( hKey) ;
1094 FIXME("Port Exist => FALSE with %u\n", ERROR_INVALID_PARAMETER);
1096 return FALSE;
1097 }
1098
1099 cbPortName = (wcslen( pi->pName ) + 1) * sizeof(WCHAR);
1100
1101 // Create a new LOCALMON_PORT structure for it.
1102 pPort = DllAllocSplMem(sizeof(LOCALMON_PORT) + cbPortName);
1103 if (!pPort)
1104 {
1105 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1106 RegCloseKey( hKey );
1107 goto Cleanup;
1108 }
1109
1110 pPort->Sig = SIGLCMPORT;
1111 pPort->hFile = INVALID_HANDLE_VALUE;
1112 pPort->pLocalmon = pLocalmon;
1113 pPort->pwszPortName = wcscpy( (PWSTR)(pPort+1), pi->pName );
1114
1115 // Insert it into the Registry list.
1116 InsertTailList(&pLocalmon->RegistryPorts, &pPort->Entry);
1117
1118 dwErrorCode = RegSetValueExW( hKey, pi->pName, 0, REG_SZ, (const BYTE *) L"", sizeof(L"") );
1119 RegCloseKey( hKey );
1120 }
1121
1122Cleanup:
1124
1125 FIXME("LocalmonAddPortEx => %u with %u\n", (dwErrorCode == ERROR_SUCCESS), GetLastError());
1126
1127 return (dwErrorCode == ERROR_SUCCESS);
1128}
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:175
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4261
FxAutoRegKey hKey
static refpint_t pi[]
Definition: server.c:96
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56

◆ LocalmonClosePort()

BOOL WINAPI LocalmonClosePort ( HANDLE  hPort)

Definition at line 456 of file ports.c.

457{
458 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
459
460 TRACE("LocalmonClosePort(%p)\n", hPort);
461
462 // Sanity checks
463 if (!pPort)
464 {
466 return FALSE;
467 }
468
469 // Close the file handle, free memory for pwszMapping and delete any NONSPOOLED port.
470 _ClosePortHandles(pPort);
471
472 // Close any open printer handle.
473 if (pPort->hPrinter)
474 {
475 ClosePrinter(pPort->hPrinter);
476 pPort->hPrinter = NULL;
477 }
478
479 // Free virtual FILE: ports which were created in LocalmonOpenPort.
480 if (pPort->PortType == PortType_FILE)
481 {
483 RemoveEntryList(&pPort->Entry);
485 DllFreeSplMem(pPort);
486 }
487
489 return TRUE;
490}
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define TRACE(s)
Definition: solgame.cpp:4
CRITICAL_SECTION Section
Definition: precomp.h:40
enum _LOCALMON_PORT::@5126 PortType
HANDLE hPrinter
Definition: precomp.h:68
static void _ClosePortHandles(PLOCALMON_PORT pPort)
Definition: ports.c:113
struct _LOCALMON_PORT * PLOCALMON_PORT
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
WINBOOL WINAPI ClosePrinter(HANDLE hPrinter)
Definition: printers.c:176

Referenced by LocalmonShutdown().

◆ LocalmonConfigurePort()

BOOL WINAPI LocalmonConfigurePort ( HANDLE  hMonitor,
LPWSTR  pName,
HWND  hWnd,
LPWSTR  pPortName 
)

Definition at line 1189 of file ports.c.

1190{
1192 FIXME("LocalmonConfigurePort : %s\n", debugstr_w( pPortName ) );
1193 return FALSE;
1194}

◆ LocalmonDeletePort()

BOOL WINAPI LocalmonDeletePort ( HANDLE  hMonitor,
LPWSTR  pName,
HWND  hWnd,
LPWSTR  pPortName 
)

Definition at line 1197 of file ports.c.

1198{
1199 DWORD res;
1200 HKEY hroot;
1201 PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
1202 PLOCALMON_PORT pPort;
1203
1204 FIXME("LocalmonDeletePort : %s\n", debugstr_w( pPortName ) );
1205
1206 res = RegOpenKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", &hroot);
1207 if ( res == ERROR_SUCCESS )
1208 {
1209 res = RegDeleteValueW(hroot, pPortName );
1210
1211 RegCloseKey(hroot);
1212
1213 pPort = _FindPort( pLocalmon, pPortName );
1214 if ( pPort )
1215 {
1217 RemoveEntryList(&pPort->Entry);
1219
1220 DllFreeSplMem(pPort);
1221 }
1222
1223 FIXME("=> %u with %u\n", res, GetLastError() );
1224 }
1225
1227 return (res == ERROR_SUCCESS);
1228}
LONG WINAPI RegDeleteValueW(HKEY hKey, LPCWSTR lpValueName)
Definition: reg.c:2330
static PLOCALMON_PORT _FindPort(PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
Definition: ports.c:356

◆ LocalmonEndDocPort()

BOOL WINAPI LocalmonEndDocPort ( HANDLE  hPort)

Definition at line 493 of file ports.c.

494{
495 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
496
497 TRACE("LocalmonEndDocPort(%p)\n", hPort);
498
499 // Sanity checks
500 if (!pPort)
501 {
503 return FALSE;
504 }
505
506 // Ending a document requires starting it first :-P
507 if (pPort->bStartedDoc)
508 {
509 // Close all ports opened in StartDocPort.
510 // That is, all but physical LPT ports (opened in OpenPort).
511 if (pPort->PortType != PortType_PhysicalLPT)
512 _ClosePortHandles(pPort);
513
514 // Report our progress.
516
517 // We're done with the printer.
518 ClosePrinter(pPort->hPrinter);
519 pPort->hPrinter = NULL;
520
521 // A new document can now be started again.
522 pPort->bStartedDoc = FALSE;
523 }
524
526 return TRUE;
527}
DWORD dwJobID
Definition: precomp.h:66
BOOL bStartedDoc
Definition: precomp.h:65
WINBOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command)
#define JOB_CONTROL_SENT_TO_PRINTER
Definition: winspool.h:335

◆ LocalmonEnumPorts()

BOOL WINAPI LocalmonEnumPorts ( HANDLE  hMonitor,
PWSTR  pName,
DWORD  Level,
PBYTE  pPorts,
DWORD  cbBuf,
PDWORD  pcbNeeded,
PDWORD  pcReturned 
)

Definition at line 530 of file ports.c.

531{
532 DWORD dwErrorCode;
533 PBYTE pPortInfoEnd;
535 PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
536 PLOCALMON_PORT pPort;
537
538 TRACE("LocalmonEnumPorts(%p, %S, %lu, %p, %lu, %p, %p)\n", hMonitor, pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
539
540 // Windows Server 2003's Local Port Monitor does absolutely no sanity checks here, not even for the Level parameter.
541 // As we implement a more modern MONITOR2-based Port Monitor, check at least our hMonitor.
542 if (!pLocalmon)
543 {
544 dwErrorCode = ERROR_INVALID_HANDLE;
545 goto Cleanup;
546 }
547
548 // Begin counting.
549 *pcbNeeded = 0;
550 *pcReturned = 0;
551
552 EnterCriticalSection(&pLocalmon->Section);
553
554 // Count the required buffer size and the number of ports.
555 for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
556 {
558
559 if (Level == 1)
561 else if (Level == 2)
563 }
564
565 // Check if the supplied buffer is large enough.
566 if (cbBuf < *pcbNeeded)
567 {
568 LeaveCriticalSection(&pLocalmon->Section);
569 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
570 goto Cleanup;
571 }
572
573 // Copy over the Port information.
574 pPortInfoEnd = &pPorts[*pcbNeeded];
575
576 for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
577 {
579
580 if (Level == 1)
581 _LocalmonGetPortLevel1(pPort, (PPORT_INFO_1W*)&pPorts, &pPortInfoEnd, NULL);
582 else if (Level == 2)
583 _LocalmonGetPortLevel2(pPort, (PPORT_INFO_2W*)&pPorts, &pPortInfoEnd, NULL);
584
585 (*pcReturned)++;
586 }
587
588 LeaveCriticalSection(&pLocalmon->Section);
589 dwErrorCode = ERROR_SUCCESS;
590
591Cleanup:
592 SetLastError(dwErrorCode);
593 return (dwErrorCode == ERROR_SUCCESS);
594}
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
static LPSTR pName
Definition: security.c:75
static void _LocalmonGetPortLevel2(PLOCALMON_PORT pPort, PPORT_INFO_2W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
Definition: ports.c:396
static void _LocalmonGetPortLevel1(PLOCALMON_PORT pPort, PPORT_INFO_1W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
Definition: ports.c:373

◆ LocalmonGetPrinterDataFromPort()

BOOL WINAPI LocalmonGetPrinterDataFromPort ( HANDLE  hPort,
DWORD  ControlID,
PWSTR  pValueName,
PWSTR  lpInBuffer,
DWORD  cbInBuffer,
PWSTR  lpOutBuffer,
DWORD  cbOutBuffer,
PDWORD  lpcbReturned 
)

Definition at line 630 of file ports.c.

631{
632 BOOL bOpenedPort = FALSE;
633 DWORD dwErrorCode;
634 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
635
636 TRACE("LocalmonGetPrinterDataFromPort(%p, %lu, %p, %p, %lu, %p, %lu, %p)\n", hPort, ControlID, pValueName, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned);
637
638 // Sanity checks
639 if (!pPort || !ControlID || !lpcbReturned)
640 {
641 dwErrorCode = ERROR_INVALID_PARAMETER;
642 goto Cleanup;
643 }
644
645 // If this is a serial port, a temporary file handle may be opened.
646 if (pPort->PortType == PortType_PhysicalCOM)
647 {
648 if (_CreateNonspooledPort(pPort))
649 {
650 bOpenedPort = TRUE;
651 }
652 else if (GetLastError() != ERROR_SUCCESS)
653 {
654 dwErrorCode = GetLastError();
655 goto Cleanup;
656 }
657 }
658 else if (pPort->hFile == INVALID_HANDLE_VALUE)
659 {
660 // All other port types need to be opened already.
661 dwErrorCode = ERROR_INVALID_PARAMETER;
662 goto Cleanup;
663 }
664
665 // Pass the parameters to DeviceIoControl.
666 if (!DeviceIoControl(pPort->hFile, ControlID, lpInBuffer, cbInBuffer, lpOutBuffer, cbOutBuffer, lpcbReturned, NULL))
667 {
668 dwErrorCode = GetLastError();
669 ERR("DeviceIoControl failed with error %lu!\n", dwErrorCode);
670 goto Cleanup;
671 }
672
673 dwErrorCode = ERROR_SUCCESS;
674
675Cleanup:
676 if (bOpenedPort)
677 _ClosePortHandles(pPort);
678
679 SetLastError(dwErrorCode);
680 return (dwErrorCode == ERROR_SUCCESS);
681}
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
static BOOL _CreateNonspooledPort(PLOCALMON_PORT pPort)
Definition: ports.c:162

◆ LocalmonOpenPort()

BOOL WINAPI LocalmonOpenPort ( HANDLE  hMonitor,
PWSTR  pName,
PHANDLE  pHandle 
)

Definition at line 684 of file ports.c.

685{
686 DWORD dwErrorCode;
687 PLOCALMON_HANDLE pLocalmon = (PLOCALMON_HANDLE)hMonitor;
688 PLOCALMON_PORT pPort;
689
690 TRACE("LocalmonOpenPort(%p, %S, %p)\n", hMonitor, pName, pHandle);
691
692 // Sanity checks
693 if (!pLocalmon || !pName || !pHandle)
694 {
695 dwErrorCode = ERROR_INVALID_PARAMETER;
696 goto Cleanup;
697 }
698
699 EnterCriticalSection(&pLocalmon->Section);
700
701 // Check if this is a FILE: port.
702 if (_wcsicmp(pName, L"FILE:") == 0)
703 {
704 // For FILE:, we create a virtual port for each request.
705 pPort = DllAllocSplMem(sizeof(LOCALMON_PORT));
706 pPort->pLocalmon = pLocalmon;
707 pPort->PortType = PortType_FILE;
709
710 // Add it to the list of file ports.
711 InsertTailList(&pLocalmon->FilePorts, &pPort->Entry);
712 }
713 else
714 {
715 // Check if the port name is valid.
716 pPort = _FindPort(pLocalmon, pName);
717 if (!pPort)
718 {
719 LeaveCriticalSection(&pLocalmon->Section);
720 dwErrorCode = ERROR_UNKNOWN_PORT;
721 goto Cleanup;
722 }
723
724 // Even if this API is called OpenPort, port file handles aren't always opened here :-P
725 // Windows only does this for physical LPT ports here to enable bidirectional communication with the printer outside of jobs (using ReadPort and WritePort).
726 // The others are only opened per job in StartDocPort.
727 if (_IsLegacyPort(pName, L"LPT"))
728 {
729 // Try to create a NONSPOOLED port and open it.
730 if (_CreateNonspooledPort(pPort))
731 {
732 // Set the transmission retry timeout for the ReadPort and WritePort calls.
733 // This also checks if this port is a physical one.
735 {
736 // This is definitely a physical LPT port!
737 pPort->PortType = PortType_PhysicalLPT;
738 }
739 else
740 {
741 // This is no physical port, so don't keep its handle open.
742 _ClosePortHandles(pPort);
743 }
744 }
745 else if (GetLastError() != ERROR_SUCCESS)
746 {
747 LeaveCriticalSection(&pLocalmon->Section);
748 dwErrorCode = GetLastError();
749 goto Cleanup;
750 }
751 }
752 else if (_IsLegacyPort(pName, L"COM"))
753 {
754 // COM ports can't be redirected over the network, so this is a physical one.
755 pPort->PortType = PortType_PhysicalCOM;
756 }
757 }
758
759 LeaveCriticalSection(&pLocalmon->Section);
760
761 // Return our fetched LOCALMON_PORT structure in the handle.
762 *pHandle = (PHANDLE)pPort;
763 dwErrorCode = ERROR_SUCCESS;
764
765Cleanup:
766 SetLastError(dwErrorCode);
767 return (dwErrorCode == ERROR_SUCCESS);
768}
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
LIST_ENTRY FilePorts
Definition: precomp.h:42
static BOOL _SetTransmissionRetryTimeout(PLOCALMON_PORT pPort)
Definition: ports.c:440
static __inline BOOL _IsLegacyPort(PCWSTR pwszPortName, PCWSTR pwszPortType)
Definition: ports.c:79
#define ERROR_UNKNOWN_PORT
Definition: winerror.h:1103

◆ LocalmonReadPort()

BOOL WINAPI LocalmonReadPort ( HANDLE  hPort,
PBYTE  pBuffer,
DWORD  cbBuffer,
PDWORD  pcbRead 
)

Definition at line 843 of file ports.c.

844{
845 BOOL bOpenedPort = FALSE;
846 DWORD dwErrorCode;
847 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
848
849 TRACE("LocalmonReadPort(%p, %p, %lu, %p)\n", hPort, pBuffer, cbBuffer, pcbRead);
850
851 // Sanity checks
852 if (!pPort || (cbBuffer && !pBuffer) || !pcbRead)
853 {
854 dwErrorCode = ERROR_INVALID_PARAMETER;
855 goto Cleanup;
856 }
857
858 // Reading is only supported for physical ports.
859 if (pPort->PortType != PortType_PhysicalCOM && pPort->PortType != PortType_PhysicalLPT)
860 {
861 dwErrorCode = ERROR_INVALID_HANDLE;
862 goto Cleanup;
863 }
864
865 // If this is a serial port, a temporary file handle may be opened.
866 if (pPort->PortType == PortType_PhysicalCOM)
867 {
868 if (_CreateNonspooledPort(pPort))
869 {
870 bOpenedPort = TRUE;
871 }
872 else if (GetLastError() != ERROR_SUCCESS)
873 {
874 dwErrorCode = GetLastError();
875 goto Cleanup;
876 }
877 }
878
879 // Pass the parameters to ReadFile.
880 if (!ReadFile(pPort->hFile, pBuffer, cbBuffer, pcbRead, NULL))
881 {
882 dwErrorCode = GetLastError();
883 ERR("ReadFile failed with error %lu!\n", dwErrorCode);
884 goto Cleanup;
885 }
886
887Cleanup:
888 if (bOpenedPort)
889 _ClosePortHandles(pPort);
890
891 SetLastError(dwErrorCode);
892 return (dwErrorCode == ERROR_SUCCESS);
893}
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
PVOID pBuffer

◆ LocalmonSetPortTimeOuts()

BOOL WINAPI LocalmonSetPortTimeOuts ( HANDLE  hPort,
LPCOMMTIMEOUTS  lpCTO,
DWORD  Reserved 
)

Definition at line 789 of file ports.c.

790{
791 BOOL bOpenedPort = FALSE;
792 DWORD dwErrorCode;
793 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
794
795 TRACE("LocalmonSetPortTimeOuts(%p, %p, %lu)\n", hPort, lpCTO, Reserved);
796
797 // Sanity checks
798 if (!pPort || !lpCTO)
799 {
800 dwErrorCode = ERROR_INVALID_PARAMETER;
801 goto Cleanup;
802 }
803
804 // If this is a serial port, a temporary file handle may be opened.
805 if (pPort->PortType == PortType_PhysicalCOM)
806 {
807 if (_CreateNonspooledPort(pPort))
808 {
809 bOpenedPort = TRUE;
810 }
811 else if (GetLastError() != ERROR_SUCCESS)
812 {
813 dwErrorCode = GetLastError();
814 goto Cleanup;
815 }
816 }
817 else if (pPort->hFile == INVALID_HANDLE_VALUE)
818 {
819 // All other port types need to be opened already.
820 dwErrorCode = ERROR_INVALID_PARAMETER;
821 goto Cleanup;
822 }
823
824 // Finally pass the parameters to SetCommTimeouts.
825 if (!SetCommTimeouts(pPort->hFile, lpCTO))
826 {
827 dwErrorCode = GetLastError();
828 ERR("SetCommTimeouts failed with error %lu!\n", dwErrorCode);
829 goto Cleanup;
830 }
831
832 dwErrorCode = ERROR_SUCCESS;
833
834Cleanup:
835 if (bOpenedPort)
836 _ClosePortHandles(pPort);
837
838 SetLastError(dwErrorCode);
839 return (dwErrorCode == ERROR_SUCCESS);
840}
_Reserved_ PVOID Reserved
Definition: winddi.h:3974

◆ LocalmonStartDocPort()

BOOL WINAPI LocalmonStartDocPort ( HANDLE  hPort,
PWSTR  pPrinterName,
DWORD  JobId,
DWORD  Level,
PBYTE  pDocInfo 
)

Definition at line 896 of file ports.c.

897{
898 DWORD dwErrorCode;
899 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo; // DOC_INFO_1W is the least common denominator for both DOC_INFO levels.
900 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
901
902 TRACE("LocalmonStartDocPort(%p, %S, %lu, %lu, %p)\n", hPort, pPrinterName, JobId, Level, pDocInfo);
903
904 // Sanity checks
905 if (!pPort || !pPrinterName || (pPort->PortType == PortType_FILE && (!pDocInfo1 || !pDocInfo1->pOutputFile || !*pDocInfo1->pOutputFile)))
906 {
907 dwErrorCode = ERROR_INVALID_PARAMETER;
908 goto Cleanup;
909 }
910
911 if (Level > 2)
912 {
913 dwErrorCode = ERROR_INVALID_LEVEL;
914 goto Cleanup;
915 }
916
917 // Calling StartDocPort multiple times isn't considered a failure, but we don't need to do anything then.
918 if (pPort->bStartedDoc)
919 {
920 dwErrorCode = ERROR_SUCCESS;
921 goto Cleanup;
922 }
923
924 // Open a handle to the given printer for later reporting our progress using SetJobW.
925 if (!OpenPrinterW(pPrinterName, &pPort->hPrinter, NULL))
926 {
927 dwErrorCode = GetLastError();
928 ERR("OpenPrinterW failed with error %lu!\n", dwErrorCode);
929 goto Cleanup;
930 }
931
932 // We need our Job ID for SetJobW as well.
933 pPort->dwJobID = JobId;
934
935 // Check the port type.
936 if (pPort->PortType == PortType_PhysicalLPT)
937 {
938 // Update the NONSPOOLED mapping if the port mapping has changed since our OpenPort call.
940 {
941 dwErrorCode = GetLastError();
942 goto Cleanup;
943 }
944
945 // Update the transmission retry timeout as well.
947 }
948 else if(pPort->PortType == PortType_FILE)
949 {
950 // This is a FILE: port. Open the output file given in the Document Info.
952 if (pPort->hFile == INVALID_HANDLE_VALUE)
953 {
954 dwErrorCode = GetLastError();
955 goto Cleanup;
956 }
957 }
958 else
959 {
960 // This can be:
961 // - a physical COM port
962 // - a non-physical LPT port (e.g. with "net use LPT1 ...")
963 // - any other port (e.g. a file or a shared printer installed as a local port)
964 //
965 // For all these cases, we try to create a NONSPOOLED port per job.
966 // If _CreateNonspooledPort reports that no NONSPOOLED port is necessary, we can just open the port name.
967 if (!_CreateNonspooledPort(pPort))
968 {
970 {
972 if (pPort->hFile == INVALID_HANDLE_VALUE)
973 {
974 dwErrorCode = GetLastError();
975 goto Cleanup;
976 }
977 }
978 else
979 {
980 dwErrorCode = GetLastError();
981 goto Cleanup;
982 }
983 }
984 }
985
986 // We were successful!
987 dwErrorCode = ERROR_SUCCESS;
988 pPort->bStartedDoc = TRUE;
989
990Cleanup:
991 SetLastError(dwErrorCode);
992 return (dwErrorCode == ERROR_SUCCESS);
993}
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
LPWSTR pOutputFile
Definition: winspool.h:617
WINBOOL WINAPI OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
Definition: printers.c:2653
struct _DOC_INFO_1W * PDOC_INFO_1W

◆ LocalmonWritePort()

BOOL WINAPI LocalmonWritePort ( HANDLE  hPort,
PBYTE  pBuffer,
DWORD  cbBuf,
PDWORD  pcbWritten 
)

Definition at line 996 of file ports.c.

997{
998 BOOL bOpenedPort = FALSE;
999 DWORD dwErrorCode;
1000 PLOCALMON_PORT pPort = (PLOCALMON_PORT)hPort;
1001
1002 TRACE("LocalmonWritePort(%p, %p, %lu, %p)\n", hPort, pBuffer, cbBuf, pcbWritten);
1003
1004 // Sanity checks
1005 if (!pPort || (cbBuf && !pBuffer) || !pcbWritten)
1006 {
1007 dwErrorCode = ERROR_INVALID_PARAMETER;
1008 goto Cleanup;
1009 }
1010
1011 // If this is a serial port, a temporary file handle may be opened.
1012 if (pPort->PortType == PortType_PhysicalCOM)
1013 {
1014 if (_CreateNonspooledPort(pPort))
1015 {
1016 bOpenedPort = TRUE;
1017 }
1018 else if (GetLastError() != ERROR_SUCCESS)
1019 {
1020 dwErrorCode = GetLastError();
1021 goto Cleanup;
1022 }
1023 }
1024 else if (pPort->hFile == INVALID_HANDLE_VALUE)
1025 {
1026 // All other port types need to be opened already.
1027 dwErrorCode = ERROR_INVALID_PARAMETER;
1028 goto Cleanup;
1029 }
1030
1031 // Pass the parameters to WriteFile.
1032 if (!WriteFile(pPort->hFile, pBuffer, cbBuf, pcbWritten, NULL))
1033 {
1034 dwErrorCode = GetLastError();
1035 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
1036 goto Cleanup;
1037 }
1038
1039 // If something was written down, we consider that a success, otherwise it's a timeout.
1040 if (*pcbWritten)
1041 dwErrorCode = ERROR_SUCCESS;
1042 else
1043 dwErrorCode = ERROR_TIMEOUT;
1044
1045Cleanup:
1046 if (bOpenedPort)
1047 _ClosePortHandles(pPort);
1048
1049 SetLastError(dwErrorCode);
1050 return (dwErrorCode == ERROR_SUCCESS);
1051}
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define ERROR_TIMEOUT
Definition: winerror.h:941

Variable Documentation

◆ cchNonspooledPrefix

const DWORD cchNonspooledPrefix = _countof(wszNonspooledPrefix) - 1
static

Definition at line 12 of file ports.c.

Referenced by _CreateNonspooledPort(), and _GetNonspooledPortName().

◆ dwPortInfo1Offsets

DWORD dwPortInfo1Offsets[]
static
Initial value:
= {
}
#define MAXDWORD
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255

Definition at line 14 of file ports.c.

Referenced by _LocalmonGetPortLevel1().

◆ dwPortInfo2Offsets

DWORD dwPortInfo2Offsets[]
static
Initial value:
= {
FIELD_OFFSET(PORT_INFO_2W, pMonitorName),
FIELD_OFFSET(PORT_INFO_2W, pDescription),
}

Definition at line 19 of file ports.c.

Referenced by _LocalmonGetPortLevel2(), and START_TEST().

◆ wszNonspooledPrefix

const WCHAR wszNonspooledPrefix[] = L"NONSPOOLED_"
static

Definition at line 11 of file ports.c.

Referenced by _CreateNonspooledPort(), and _GetNonspooledPortName().