2 * PROJECT: ReactOS Local Port Monitor
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Main functions
5 * COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
13 PCWSTR pwszLocalMonitor
;
17 static MONITOR2 _MonitorFunctions
= {
18 sizeof(MONITOR2
), // cbSize
19 LocalmonEnumPorts
, // pfnEnumPorts
20 LocalmonOpenPort
, // pfnOpenPort
21 NULL
, // pfnOpenPortEx
22 LocalmonStartDocPort
, // pfnStartDocPort
23 LocalmonWritePort
, // pfnWritePort
24 LocalmonReadPort
, // pfnReadPort
25 LocalmonEndDocPort
, // pfnEndDocPort
26 LocalmonClosePort
, // pfnClosePort
29 NULL
, // pfnConfigurePort
30 NULL
, // pfnDeletePort
31 LocalmonGetPrinterDataFromPort
, // pfnGetPrinterDataFromPort
32 LocalmonSetPortTimeOuts
, // pfnSetPortTimeOuts
33 LocalmonXcvOpenPort
, // pfnXcvOpenPort
34 LocalmonXcvDataPort
, // pfnXcvDataPort
35 LocalmonXcvClosePort
, // pfnXcvClosePort
36 LocalmonShutdown
, // pfnShutdown
37 NULL
, // pfnSendRecvBidiDataFromPort
44 * Checks if the given port name is a virtual Ne port.
45 * A virtual Ne port may appear in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports and can have the formats
46 * Ne00:, Ne01:, Ne-02:, Ne456:
47 * This check is extra picky to not cause false positives (like file name ports starting with "Ne").
50 * The port name to check.
53 * TRUE if this is definitely a virtual Ne port, FALSE if not.
56 _IsNEPort(PCWSTR pwszPortName
)
58 PCWSTR p
= pwszPortName
;
60 // First character needs to be 'N' (uppercase or lowercase)
61 if (*p
!= L
'N' && *p
!= L
'n')
64 // Next character needs to be 'E' (uppercase or lowercase)
66 if (*p
!= L
'E' && *p
!= L
'e')
69 // An optional hyphen may follow now.
74 // Now an arbitrary number of digits may follow.
75 while (*p
>= L
'0' && *p
<= L
'9')
78 // Finally, the virtual Ne port must be terminated by a colon.
82 // If this is the end of the string, we have a virtual Ne port.
88 _LoadResources(HINSTANCE hinstDLL
)
90 LoadStringW(hinstDLL
, IDS_LOCAL_MONITOR
, (PWSTR
)&pwszLocalMonitor
, 0);
91 cbLocalMonitor
= (wcslen(pwszLocalMonitor
) + 1) * sizeof(WCHAR
);
93 LoadStringW(hinstDLL
, IDS_LOCAL_PORT
, (PWSTR
)&pwszLocalPort
, 0);
94 cbLocalPort
= (wcslen(pwszLocalPort
) + 1) * sizeof(WCHAR
);
98 DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
102 case DLL_PROCESS_ATTACH
:
103 DisableThreadLibraryCalls(hinstDLL
);
104 _LoadResources(hinstDLL
);
112 LocalmonShutdown(HANDLE hMonitor
)
114 PLOCALMON_HANDLE pLocalmon
;
115 PLOCALMON_PORT pPort
;
118 TRACE("LocalmonShutdown(%p)\n", hMonitor
);
120 pLocalmon
= (PLOCALMON_HANDLE
)hMonitor
;
122 // Close all virtual file ports.
123 while (!IsListEmpty(&pLocalmon
->FilePorts
))
125 pPort
= CONTAINING_RECORD(&pLocalmon
->FilePorts
.Flink
, LOCALMON_PORT
, Entry
);
126 LocalmonClosePort((HANDLE
)pPort
);
129 // Do the same for the open Xcv ports.
130 while (!IsListEmpty(&pLocalmon
->XcvHandles
))
132 pXcv
= CONTAINING_RECORD(&pLocalmon
->XcvHandles
.Flink
, LOCALMON_XCV
, Entry
);
133 LocalmonXcvClosePort((HANDLE
)pXcv
);
136 // Now close all registry ports, remove them from the list and free their memory.
137 while (!IsListEmpty(&pLocalmon
->RegistryPorts
))
139 pPort
= CONTAINING_RECORD(&pLocalmon
->RegistryPorts
.Flink
, LOCALMON_PORT
, Entry
);
140 LocalmonClosePort((HANDLE
)pPort
);
141 RemoveEntryList(&pPort
->Entry
);
142 DllFreeSplMem(pPort
);
145 // Finally clean the LOCALMON_HANDLE structure itself.
146 DeleteCriticalSection(&pLocalmon
->Section
);
147 DllFreeSplMem(pLocalmon
);
151 InitializePrintMonitor2(PMONITORINIT pMonitorInit
, PHANDLE phMonitor
)
153 DWORD cchMaxPortName
;
159 PMONITOR2 pReturnValue
= NULL
;
160 PLOCALMON_HANDLE pLocalmon
;
161 PLOCALMON_PORT pPort
= NULL
;
163 TRACE("InitializePrintMonitor2(%p, %p)\n", pMonitorInit
, phMonitor
);
165 // Create a new LOCALMON_HANDLE structure.
166 pLocalmon
= DllAllocSplMem(sizeof(LOCALMON_HANDLE
));
167 InitializeCriticalSection(&pLocalmon
->Section
);
168 InitializeListHead(&pLocalmon
->FilePorts
);
169 InitializeListHead(&pLocalmon
->RegistryPorts
);
170 InitializeListHead(&pLocalmon
->XcvHandles
);
172 // The Local Spooler Port Monitor doesn't need to care about the given registry key and functions.
173 // Instead it uses a well-known registry key for getting its information about local ports. Open this one.
174 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", 0, KEY_READ
, &hKey
);
175 if (dwErrorCode
!= ERROR_SUCCESS
)
177 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
181 // Get the number of ports and the length of the largest port name.
182 dwErrorCode
= (DWORD
)RegQueryInfoKeyW(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &dwPortCount
, &cchMaxPortName
, NULL
, NULL
, NULL
);
183 if (dwErrorCode
!= ERROR_SUCCESS
)
185 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode
);
189 // Loop through all ports.
190 for (i
= 0; i
< dwPortCount
; i
++)
192 // Allocate memory for a new LOCALMON_PORT structure and its name.
193 pPort
= DllAllocSplMem(sizeof(LOCALMON_PORT
) + (cchMaxPortName
+ 1) * sizeof(WCHAR
));
196 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
197 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
201 pPort
->pLocalmon
= pLocalmon
;
202 pPort
->hFile
= INVALID_HANDLE_VALUE
;
203 pPort
->pwszPortName
= (PWSTR
)((PBYTE
)pPort
+ sizeof(LOCALMON_PORT
));
205 // Get the port name.
206 cchPortName
= cchMaxPortName
+ 1;
207 dwErrorCode
= (DWORD
)RegEnumValueW(hKey
, i
, pPort
->pwszPortName
, &cchPortName
, NULL
, NULL
, NULL
, NULL
);
208 if (dwErrorCode
!= ERROR_SUCCESS
)
210 ERR("RegEnumValueW failed with status %lu!\n", dwErrorCode
);
214 // pwszPortName can be one of the following to be valid for this Port Monitor:
215 // COMx: - Physical COM port
216 // LPTx: - Physical LPT port (or redirected one using "net use LPT1 ...")
217 // FILE: - Opens a prompt that asks for an output filename
218 // C:\bla.txt - Redirection into the file "C:\bla.txt"
219 // \\COMPUTERNAME\PrinterName - Redirection to a shared network printer installed as a local port
221 // We can't detect valid and invalid ones by the name, so we can only exclude empty ports and the virtual "Ne00:", "Ne01:", ... ports.
222 // Skip the invalid ones here.
223 if (!cchPortName
|| _IsNEPort(pPort
->pwszPortName
))
225 DllFreeSplMem(pPort
);
229 // Add it to the list.
230 InsertTailList(&pLocalmon
->RegistryPorts
, &pPort
->Entry
);
232 // Don't let the cleanup routine free this.
236 // Return our handle and the Print Monitor functions.
237 *phMonitor
= (HANDLE
)pLocalmon
;
238 pReturnValue
= &_MonitorFunctions
;
239 dwErrorCode
= ERROR_SUCCESS
;
243 DllFreeSplMem(pPort
);
245 SetLastError(dwErrorCode
);