ReactOS 0.4.16-dev-197-g92996da
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
11static const WCHAR wszNonspooledPrefix[] = L"NONSPOOLED_";
13
17};
18
20 FIELD_OFFSET(PORT_INFO_2W, pPortName),
21 FIELD_OFFSET(PORT_INFO_2W, pMonitorName),
22 FIELD_OFFSET(PORT_INFO_2W, pDescription),
24};
25
26
43static __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
78static __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
112static 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);
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}
145
161static 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);
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}
354
355static PLOCALMON_PORT
356_FindPort(PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
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}
371
372static 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
395static 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
439static 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
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
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
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}
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 */
630LocalmonGetPrinterDataFromPort(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
675Cleanup:
676 if (bOpenedPort)
677 _ClosePortHandles(pPort);
678
679 SetLastError(dwErrorCode);
680 return (dwErrorCode == ERROR_SUCCESS);
681}
682
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}
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 */
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}
841
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}
894
896LocalmonStartDocPort(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 {
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}
994
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}
1052
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}
1129
1130// Fallback Throw Back code....
1131//
1132// This is pre-w2k support, seems to be moved into LocalUI.
1133//
1134//
1135
1137LocalmonAddPort( 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
1183Cleanup:
1185 return (res == ERROR_SUCCESS);
1186}
1187
1190{
1192 FIXME("LocalmonConfigurePort : %s\n", debugstr_w( pPortName ) );
1193 return FALSE;
1194}
1195
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}
static UNICODE_STRING PortName
HWND hWnd
Definition: settings.c:17
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
PBYTE WINAPI PackStrings(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
#define RegCloseKey(hKey)
Definition: registry.h:49
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:175
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define ERROR_SUCCESS
Definition: deptool.c:10
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 NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
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
LONG WINAPI RegDeleteValueW(HKEY hKey, LPCWSTR lpValueName)
Definition: reg.c:2330
#define CloseHandle
Definition: compat.h:739
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetLastError(x)
Definition: compat.h:752
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
#define CreateFileW
Definition: compat.h:741
#define FILE_SHARE_READ
Definition: compat.h:136
BOOL WINAPI DefineDosDeviceW(DWORD dwFlags, LPCWSTR lpDeviceName, LPCWSTR lpTargetPath)
Definition: dosdev.c:232
DWORD WINAPI QueryDosDeviceW(LPCWSTR lpDeviceName, LPWSTR lpTargetPath, DWORD ucchMax)
Definition: dosdev.c:542
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
Definition: comm.c:1062
BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
Definition: comm.c:1020
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4262
static const WCHAR Cleanup[]
Definition: register.c:80
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
GLuint res
Definition: glext.h:9613
GLfloat GLfloat p
Definition: glext.h:8902
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define debugstr_w
Definition: kernel32.h:32
#define REG_SZ
Definition: layer.c:22
#define CREATE_ALWAYS
Definition: disk.h:72
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
static LPSTR pName
Definition: security.c:75
static refpint_t pi[]
Definition: server.c:96
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define GENERIC_WRITE
Definition: nt_native.h:90
#define MAXDWORD
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
DWORD * PDWORD
Definition: pedump.c:68
HANDLE WINAPI RevertToPrinterSelf(VOID)
Definition: context.c:64
BOOL WINAPI ImpersonatePrinterClient(_In_ HANDLE hToken)
PVOID pBuffer
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_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)
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
base of all file and directory entries
Definition: entries.h:83
DWORD WriteTotalTimeoutConstant
Definition: winbase.h:737
LPWSTR pOutputFile
Definition: winspool.h:617
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
CRITICAL_SECTION Section
Definition: precomp.h:40
LIST_ENTRY FilePorts
Definition: precomp.h:42
LIST_ENTRY RegistryPorts
Definition: precomp.h:43
PWSTR pwszPortName
Definition: precomp.h:55
DWORD Sig
Definition: precomp.h:57
PLOCALMON_HANDLE pLocalmon
Definition: precomp.h:56
PWSTR pwszMapping
Definition: precomp.h:69
LIST_ENTRY Entry
Definition: precomp.h:54
DWORD dwJobID
Definition: precomp.h:66
BOOL bStartedDoc
Definition: precomp.h:65
enum _LOCALMON_PORT::@5118 PortType
HANDLE hPrinter
Definition: precomp.h:68
HANDLE hFile
Definition: precomp.h:67
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * LPBYTE
Definition: typedefs.h:53
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
BOOL WINAPI DllFreeSplStr(PWSTR pwszString)
Definition: memory.c:130
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput)
Definition: memory.c:56
PCWSTR pwszLocalMonitor
Definition: main.c:13
DWORD cbLocalMonitor
Definition: main.c:11
DWORD cbLocalPort
Definition: main.c:12
PCWSTR pwszLocalPort
Definition: main.c:14
BOOL WINAPI LocalmonStartDocPort(HANDLE hPort, PWSTR pPrinterName, DWORD JobId, DWORD Level, PBYTE pDocInfo)
Definition: ports.c:896
static __inline DWORD _GetNonspooledPortName(PCWSTR pwszPortNameWithoutColon, PWSTR *ppwszNonspooledPortName)
Definition: ports.c:44
static DWORD dwPortInfo1Offsets[]
Definition: ports.c:14
BOOL WINAPI LocalmonDeletePort(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName)
Definition: ports.c:1197
static void _ClosePortHandles(PLOCALMON_PORT pPort)
Definition: ports.c:113
BOOL WINAPI LocalmonAddPortEx(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
Definition: ports.c:1054
static PLOCALMON_PORT _FindPort(PLOCALMON_HANDLE pLocalmon, PCWSTR pwszPortName)
Definition: ports.c:356
BOOL WINAPI LocalmonOpenPort(HANDLE hMonitor, PWSTR pName, PHANDLE pHandle)
Definition: ports.c:684
static void _LocalmonGetPortLevel2(PLOCALMON_PORT pPort, PPORT_INFO_2W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
Definition: ports.c:396
BOOL WINAPI LocalmonAddPort(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
Definition: ports.c:1137
BOOL WINAPI LocalmonWritePort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuf, PDWORD pcbWritten)
Definition: ports.c:996
BOOL WINAPI LocalmonEnumPorts(HANDLE hMonitor, PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: ports.c:530
BOOL WINAPI LocalmonReadPort(HANDLE hPort, PBYTE pBuffer, DWORD cbBuffer, PDWORD pcbRead)
Definition: ports.c:843
static BOOL _CreateNonspooledPort(PLOCALMON_PORT pPort)
Definition: ports.c:162
static void _LocalmonGetPortLevel1(PLOCALMON_PORT pPort, PPORT_INFO_1W *ppPortInfo, PBYTE *ppPortInfoEnd, PDWORD pcbNeeded)
Definition: ports.c:373
static const DWORD cchNonspooledPrefix
Definition: ports.c:12
static BOOL _SetTransmissionRetryTimeout(PLOCALMON_PORT pPort)
Definition: ports.c:440
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
BOOL WINAPI LocalmonEndDocPort(HANDLE hPort)
Definition: ports.c:493
BOOL WINAPI LocalmonConfigurePort(HANDLE hMonitor, LPWSTR pName, HWND hWnd, LPWSTR pPortName)
Definition: ports.c:1189
static const WCHAR wszNonspooledPrefix[]
Definition: ports.c:11
static __inline BOOL _IsLegacyPort(PCWSTR pwszPortName, PCWSTR pwszPortType)
Definition: ports.c:79
BOOL WINAPI LocalmonClosePort(HANDLE hPort)
Definition: ports.c:456
BOOL WINAPI LocalmonSetPortTimeOuts(HANDLE hPort, LPCOMMTIMEOUTS lpCTO, DWORD Reserved)
Definition: ports.c:789
#define SIGLCMPORT
Definition: precomp.h:31
struct _LOCALMON_PORT * PLOCALMON_PORT
DWORD GetPortNameWithoutColon(PCWSTR pwszPortName, PWSTR *ppwszPortNameWithoutColon)
Definition: tools.c:142
struct _LOCALMON_HANDLE * PLOCALMON_HANDLE
DWORD GetLPTTransmissionRetryTimeout(VOID)
Definition: tools.c:85
BOOL DoesPortExist(PCWSTR pwszPortName)
Definition: tools.c:24
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define DDD_RAW_TARGET_PATH
Definition: winbase.h:548
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
#define CopyMemory
Definition: winbase.h:1734
#define DDD_REMOVE_DEFINITION
Definition: winbase.h:549
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3828
_Reserved_ PVOID Reserved
Definition: winddi.h:3974
#define WINAPI
Definition: msvc.h:6
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
#define ERROR_UNKNOWN_PORT
Definition: winerror.h:1103
#define ERROR_TIMEOUT
Definition: winerror.h:941
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define PORT_TYPE_READ
Definition: winspool.h:777
WINBOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command)
#define PORT_TYPE_WRITE
Definition: winspool.h:776
WINBOOL WINAPI OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
Definition: printers.c:2653
WINBOOL WINAPI ClosePrinter(HANDLE hPrinter)
Definition: printers.c:176
struct _PORT_INFO_1W PORT_INFO_1W
struct _DOC_INFO_1W * PDOC_INFO_1W
struct _PORT_INFO_2W PORT_INFO_2W
#define JOB_CONTROL_SENT_TO_PRINTER
Definition: winspool.h:335
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
unsigned char BYTE
Definition: xxhash.c:193