ReactOS  0.4.15-dev-1070-ge1a01de
ports.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Local Port Monitor
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Functions related to ports
5  * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 // Local Constants
11 static const WCHAR wszNonspooledPrefix[] = L"NONSPOOLED_";
13 
16  MAXDWORD
17 };
18 
20  FIELD_OFFSET(PORT_INFO_2W, pPortName),
21  FIELD_OFFSET(PORT_INFO_2W, pMonitorName),
22  FIELD_OFFSET(PORT_INFO_2W, pDescription),
23  MAXDWORD
24 };
25 
26 
43 static __inline DWORD
44 _GetNonspooledPortName(PCWSTR pwszPortNameWithoutColon, PWSTR* ppwszNonspooledPortName)
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 }
62 
78 static __inline BOOL
79 _IsLegacyPort(PCWSTR pwszPortName, PCWSTR pwszPortType)
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 }
102 
112 static void
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);
124  pPort->hFile = INVALID_HANDLE_VALUE;
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.
131  DllFreeSplStr(pPort->pwszMapping);
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 }
145 
161 static BOOL
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);
253  pPort->hFile = INVALID_HANDLE_VALUE;
254 
255  DllFreeSplStr(pPort->pwszMapping);
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\"!", 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.
296  ImpersonatePrinterClient(hToken);
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 
332 Cleanup:
333  if (hToken)
334  ImpersonatePrinterClient(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 }
354 
355 static PLOCALMON_PORT
356 _FindPort(PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
357 {
358  PLIST_ENTRY pEntry;
359  PLOCALMON_PORT pPort;
360 
361  for (pEntry = pLocalmon->RegistryPorts.Flink; pEntry != &pLocalmon->RegistryPorts; pEntry = pEntry->Flink)
362  {
363  pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
364 
365  if (wcscmp(pPort->pwszPortName, pwszPortName) == 0)
366  return pPort;
367  }
368 
369  return NULL;
370 }
371 
372 static void
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 }
394 
395 static void
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 }
427 
439 static BOOL
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 }
454 
455 BOOL WINAPI
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 }
491 
492 BOOL WINAPI
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 }
528 
529 BOOL WINAPI
530 LocalmonEnumPorts(HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
531 {
532  DWORD dwErrorCode;
533  PBYTE pPortInfoEnd;
534  PLIST_ENTRY pEntry;
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  {
557  pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
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  {
578  pPort = CONTAINING_RECORD(pEntry, LOCALMON_PORT, Entry);
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 
591 Cleanup:
592  SetLastError(dwErrorCode);
593  return (dwErrorCode == ERROR_SUCCESS);
594 }
595 
596 /*
597  * @name LocalmonGetPrinterDataFromPort
598  *
599  * Performs a DeviceIoControl call for the given port.
600  *
601  * @param hPort
602  * The port to operate on.
603  *
604  * @param ControlID
605  * The dwIoControlCode passed to DeviceIoControl. Must not be zero!
606  *
607  * @param pValueName
608  * This parameter is ignored.
609  *
610  * @param lpInBuffer
611  * The lpInBuffer passed to DeviceIoControl.
612  *
613  * @param cbInBuffer
614  * The nInBufferSize passed to DeviceIoControl.
615  *
616  * @param lpOutBuffer
617  * The lpOutBuffer passed to DeviceIoControl.
618  *
619  * @param cbOutBuffer
620  * The nOutBufferSize passed to DeviceIoControl.
621  *
622  * @param lpcbReturned
623  * The lpBytesReturned passed to DeviceIoControl. Must not be zero!
624  *
625  * @return
626  * TRUE if the DeviceIoControl call was successful, FALSE otherwise.
627  * A more specific error code can be obtained through GetLastError.
628  */
629 BOOL WINAPI
630 LocalmonGetPrinterDataFromPort(HANDLE hPort, DWORD ControlID, PWSTR pValueName, PWSTR lpInBuffer, DWORD cbInBuffer, PWSTR lpOutBuffer, DWORD cbOutBuffer, PDWORD lpcbReturned)
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 
675 Cleanup:
676  if (bOpenedPort)
677  _ClosePortHandles(pPort);
678 
679  SetLastError(dwErrorCode);
680  return (dwErrorCode == ERROR_SUCCESS);
681 }
682 
683 BOOL WINAPI
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;
708  pPort->hFile = INVALID_HANDLE_VALUE;
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.
734  if (_SetTransmissionRetryTimeout(pPort))
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 
765 Cleanup:
766  SetLastError(dwErrorCode);
767  return (dwErrorCode == ERROR_SUCCESS);
768 }
769 
770 /*
771  * @name LocalmonSetPortTimeOuts
772  *
773  * Performs a SetCommTimeouts call for the given port.
774  *
775  * @param hPort
776  * The port to operate on.
777  *
778  * @param lpCTO
779  * Pointer to a COMMTIMEOUTS structure that is passed to SetCommTimeouts.
780  *
781  * @param Reserved
782  * Reserved parameter, must be 0.
783  *
784  * @return
785  * TRUE if the SetCommTimeouts call was successful, FALSE otherwise.
786  * A more specific error code can be obtained through GetLastError.
787  */
788 BOOL WINAPI
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 
834 Cleanup:
835  if (bOpenedPort)
836  _ClosePortHandles(pPort);
837 
838  SetLastError(dwErrorCode);
839  return (dwErrorCode == ERROR_SUCCESS);
840 }
841 
842 BOOL WINAPI
843 LocalmonReadPort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead)
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 
887 Cleanup:
888  if (bOpenedPort)
889  _ClosePortHandles(pPort);
890 
891  SetLastError(dwErrorCode);
892  return (dwErrorCode == ERROR_SUCCESS);
893 }
894 
895 BOOL WINAPI
896 LocalmonStartDocPort(HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo)
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  {
969  if (GetLastError() == ERROR_SUCCESS)
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 
990 Cleanup:
991  SetLastError(dwErrorCode);
992  return (dwErrorCode == ERROR_SUCCESS);
993 }
994 
995 BOOL WINAPI
996 LocalmonWritePort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten)
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 
1045 Cleanup:
1046  if (bOpenedPort)
1047  _ClosePortHandles(pPort);
1048 
1049  SetLastError(dwErrorCode);
1050  return (dwErrorCode == ERROR_SUCCESS);
1051 }
1052 
1053 BOOL WINAPI
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 
1122 Cleanup:
1123  if (dwErrorCode != ERROR_SUCCESS) SetLastError(ERROR_INVALID_PARAMETER);
1124 
1125  FIXME("LocalmonAddPortEx => %u with %u\n", (dwErrorCode == ERROR_SUCCESS), GetLastError());
1126 
1127  return (dwErrorCode == ERROR_SUCCESS);
1128 }
1129 
1130 // Fallback Throw Back code....
1131 //
1132 // This is pre-w2k support, seems to be moved into LocalUI.
1133 //
1134 //
1135 
1136 BOOL WINAPI
1137 LocalmonAddPort( HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pMonitorName )
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 
1183 Cleanup:
1184  SetLastError(res);
1185  return (res == ERROR_SUCCESS);
1186 }
1187 
1188 BOOL WINAPI
1190 {
1192  FIXME("LocalmonConfigurePort : %s\n", debugstr_w( pPortName ) );
1193  return FALSE;
1194 }
1195 
1196 BOOL WINAPI
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 
1226  SetLastError(res);
1227  return (res == ERROR_SUCCESS);
1228 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
const uint16_t * PCWSTR
Definition: typedefs.h:57
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput)
Definition: memory.c:56
#define CloseHandle
Definition: compat.h:487
static __inline BOOL _IsLegacyPort(PCWSTR pwszPortName, PCWSTR pwszPortType)
Definition: ports.c:79
#define ERROR_SUCCESS
Definition: deptool.c:10
LIST_ENTRY Entry
Definition: precomp.h:54
BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
Definition: comm.c:1060
static PLOCALMON_PORT _FindPort(PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
Definition: ports.c:356
#define TRUE
Definition: types.h:120
#define PORT_TYPE_WRITE
Definition: winspool.h:776
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:505
#define ERROR_TIMEOUT
Definition: winerror.h:941
uint16_t * PWSTR
Definition: typedefs.h:56
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
LPWSTR pOutputFile
Definition: winspool.h:617
BOOL WINAPI LocalmonClosePort(HANDLE hPort)
Definition: ports.c:456
_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)
HWND hWnd
Definition: settings.c:17
BOOL WINAPI LocalmonWritePort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten)
Definition: ports.c:996
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:479
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
enum _LOCALMON_PORT::@4255 PortType
DWORD cbLocalPort
Definition: main.c:12
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define InsertTailList(ListHead, Entry)
BOOL WINAPI LocalmonSetPortTimeOuts(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD Reserved)
Definition: ports.c:789
#define FILE_SHARE_READ
Definition: compat.h:136
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:194
DWORD Sig
Definition: precomp.h:57
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
DWORD GetLPTTransmissionRetryTimeout(VOID)
Definition: tools.c:85
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:53
#define FALSE
Definition: types.h:117
BOOL WINAPI LocalmonDeletePort(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName)
Definition: ports.c:1197
unsigned int BOOL
Definition: ntddk_ex.h:94
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3296
#define GENERIC_WRITE
Definition: nt_native.h:90
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:111
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:173
#define ERROR_UNKNOWN_PORT
Definition: winerror.h:1103
BOOL WINAPI LocalmonGetPrinterDataFromPort(HANDLE hPort, DWORD ControlID, PWSTR pValueName, PWSTR lpInBuffer, DWORD cbInBuffer, PWSTR lpOutBuffer, DWORD cbOutBuffer, PDWORD lpcbReturned)
Definition: ports.c:630
static DWORD dwPortInfo2Offsets[]
Definition: ports.c:19
WINBOOL WINAPI ClosePrinter(HANDLE hPrinter)
Definition: printers.c:176
BOOL WINAPI LocalmonOpenPort(HANDLE hMonitor, PWSTR pName, PHANDLE pHandle)
Definition: ports.c:684
smooth NULL
Definition: ftsmooth.c:416
PVOID pBuffer
#define SIGLCMPORT
Definition: precomp.h:31
DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax)
Definition: dosdev.c:542
#define MAXDWORD
BOOL bStartedDoc
Definition: precomp.h:65
_Reserved_ PVOID Reserved
Definition: winddi.h:3974
BOOL WINAPI LocalmonAddPort(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
Definition: ports.c:1137
BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
Definition: comm.c:1018
HANDLE WINAPI RevertToPrinterSelf(VOID)
Definition: context.c:64
static void _ClosePortHandles(PLOCALMON_PORT pPort)
Definition: ports.c:113
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
BOOL WINAPI LocalmonStartDocPort(HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo)
Definition: ports.c:896
static const DWORD cchNonspooledPrefix
Definition: ports.c:12
LIST_ENTRY FilePorts
Definition: precomp.h:42
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:4895
BOOL DoesPortExist(PCWSTR pwszPortName)
Definition: tools.c:24
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
static BOOL _CreateNonspooledPort(PLOCALMON_PORT pPort)
Definition: ports.c:162
LIST_ENTRY RegistryPorts
Definition: precomp.h:43
#define TRACE(s)
Definition: solgame.cpp:4
static LPSTR pName
Definition: security.c:75
BOOL WINAPI LocalmonEnumPorts(HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: ports.c:530
PWSTR pwszPortName
Definition: precomp.h:55
__wchar_t WCHAR
Definition: xmlstorage.h:180
PBYTE WINAPI PackStrings(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
static refpint_t pi[]
Definition: server.c:96
static void _LocalmonGetPortLevel2(PLOCALMON_PORT pPort, PPORT_INFO_2W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
Definition: ports.c:396
#define _countof(array)
Definition: sndvol32.h:68
PLOCALMON_HANDLE pLocalmon
Definition: precomp.h:56
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
#define CopyMemory
Definition: winbase.h:1646
PWSTR pwszMapping
Definition: precomp.h:69
unsigned long DWORD
Definition: ntddk_ex.h:95
struct _PORT_INFO_2W PORT_INFO_2W
#define SetLastError(x)
Definition: compat.h:500
CRITICAL_SECTION Section
Definition: precomp.h:40
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:454
#define JOB_CONTROL_SENT_TO_PRINTER
Definition: winspool.h:335
static __inline DWORD _GetNonspooledPortName(PCWSTR pwszPortNameWithoutColon, PWSTR *ppwszNonspooledPortName)
Definition: ports.c:44
#define GENERIC_READ
Definition: compat.h:135
Definition: typedefs.h:119
DWORD dwJobID
Definition: precomp.h:66
static const WCHAR Cleanup[]
Definition: register.c:80
HANDLE hFile
Definition: precomp.h:67
unsigned char BYTE
Definition: xxhash.c:193
BOOL WINAPI DefineDosDeviceW(DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath)
Definition: dosdev.c:232
PCWSTR pwszLocalPort
Definition: main.c:14
#define ERR(fmt,...)
Definition: debug.h:110
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
WINBOOL WINAPI OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
Definition: printers.c:2624
#define CREATE_ALWAYS
Definition: disk.h:72
static DWORD dwPortInfo1Offsets[]
Definition: ports.c:14
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
#define DDD_RAW_TARGET_PATH
Definition: winbase.h:504
#define PORT_TYPE_READ
Definition: winspool.h:777
LONG WINAPI RegDeleteValueW(HKEY hKey, LPCWSTR lpValueName)
Definition: reg.c:2355
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3827
BOOL WINAPI LocalmonConfigurePort(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName)
Definition: ports.c:1189
static void _LocalmonGetPortLevel1(PLOCALMON_PORT pPort, PPORT_INFO_1W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
Definition: ports.c:373
PCWSTR pwszLocalMonitor
Definition: main.c:13
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define ReadFile(a, b, c, d, e)
Definition: compat.h:490
HANDLE hPrinter
Definition: precomp.h:68
DWORD * PDWORD
Definition: pedump.c:68
BOOL WINAPI DllFreeSplStr(PWSTR pwszString)
Definition: memory.c:130
#define CreateFileW
Definition: compat.h:489
BOOL WINAPI LocalmonEndDocPort(HANDLE hPort)
Definition: ports.c:493
GLuint res
Definition: glext.h:9613
struct _DOC_INFO_1W * PDOC_INFO_1W
BOOL WINAPI ImpersonatePrinterClient(_In_ HANDLE hToken)
static const WCHAR wszNonspooledPrefix[]
Definition: ports.c:11
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
BOOL WINAPI LocalmonAddPortEx(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
Definition: ports.c:1054
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
BOOL WINAPI LocalmonReadPort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead)
Definition: ports.c:843
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
DWORD WriteTotalTimeoutConstant
Definition: winbase.h:691
static BOOL _SetTransmissionRetryTimeout(PLOCALMON_PORT pPort)
Definition: ports.c:440
WINBOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command)
BYTE * PBYTE
Definition: pedump.c:66
DWORD cbLocalMonitor
Definition: main.c:11
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
struct _PORT_INFO_1W PORT_INFO_1W
base of all file and directory entries
Definition: entries.h:82
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
struct _LOCALMON_HANDLE * PLOCALMON_HANDLE
DWORD GetPortNameWithoutColon(PCWSTR pwszPortName, PWSTR *ppwszPortNameWithoutColon)
Definition: tools.c:142
IN PUNICODE_STRING PortName
Definition: conport.c:35
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
struct _LOCALMON_PORT * PLOCALMON_PORT
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define REG_SZ
Definition: layer.c:22