[LOCALMON]
[reactos.git] / reactos / win32ss / printing / monitors / localmon / main.c
1 /*
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>
6 */
7
8 #include "precomp.h"
9
10 // Global Variables
11 DWORD cbLocalMonitor;
12 DWORD cbLocalPort;
13 PCWSTR pwszLocalMonitor;
14 PCWSTR pwszLocalPort;
15
16 // Local Constants
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
27 NULL, // pfnAddPort
28 NULL, // pfnAddPortEx
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
38 };
39
40
41 static void
42 _LoadResources(HINSTANCE hinstDLL)
43 {
44 LoadStringW(hinstDLL, IDS_LOCAL_MONITOR, (PWSTR)&pwszLocalMonitor, 0);
45 cbLocalMonitor = (wcslen(pwszLocalMonitor) + 1) * sizeof(WCHAR);
46
47 LoadStringW(hinstDLL, IDS_LOCAL_PORT, (PWSTR)&pwszLocalPort, 0);
48 cbLocalPort = (wcslen(pwszLocalPort) + 1) * sizeof(WCHAR);
49 }
50
51 BOOL WINAPI
52 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
53 {
54 switch (fdwReason)
55 {
56 case DLL_PROCESS_ATTACH:
57 DisableThreadLibraryCalls(hinstDLL);
58 _LoadResources(hinstDLL);
59 break;
60 }
61
62 return TRUE;
63 }
64
65 void WINAPI
66 LocalmonShutdown(HANDLE hMonitor)
67 {
68 PLOCALMON_HANDLE pLocalmon;
69 PLOCALMON_PORT pPort;
70
71 pLocalmon = (PLOCALMON_HANDLE)hMonitor;
72
73 // Close all virtual file ports.
74 while (!IsListEmpty(&pLocalmon->FilePorts))
75 {
76 pPort = CONTAINING_RECORD(&pLocalmon->FilePorts.Flink, LOCALMON_PORT, Entry);
77 LocalmonClosePort((HANDLE)pPort);
78 }
79
80 // Now close all regular ports and remove them from the list.
81 while (!IsListEmpty(&pLocalmon->Ports))
82 {
83 pPort = CONTAINING_RECORD(&pLocalmon->Ports.Flink, LOCALMON_PORT, Entry);
84 RemoveEntryList(&pPort->Entry);
85 LocalmonClosePort((HANDLE)pPort);
86 }
87
88 // Finally free the memory for the LOCALMON_HANDLE structure itself.
89 DllFreeSplMem(pLocalmon);
90 }
91
92 PMONITOR2 WINAPI
93 InitializePrintMonitor2(PMONITORINIT pMonitorInit, PHANDLE phMonitor)
94 {
95 DWORD cchMaxPortName;
96 DWORD cchPortName;
97 DWORD dwErrorCode;
98 DWORD dwPortCount;
99 DWORD i;
100 HKEY hKey;
101 PMONITOR2 pReturnValue = NULL;
102 PLOCALMON_HANDLE pLocalmon;
103 PLOCALMON_PORT pPort = NULL;
104
105 // Create a new LOCALMON_HANDLE structure.
106 pLocalmon = DllAllocSplMem(sizeof(LOCALMON_HANDLE));
107 InitializeListHead(&pLocalmon->FilePorts);
108 InitializeListHead(&pLocalmon->Ports);
109
110 // The Local Spooler Port Monitor doesn't need to care about the given registry key and functions.
111 // Instead it uses a well-known registry key for getting its information about local ports. Open this one.
112 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports", 0, KEY_READ, &hKey);
113 if (dwErrorCode != ERROR_SUCCESS)
114 {
115 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
116 goto Cleanup;
117 }
118
119 // Get the number of ports and the length of the largest port name.
120 dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwPortCount, &cchMaxPortName, NULL, NULL, NULL);
121 if (dwErrorCode != ERROR_SUCCESS)
122 {
123 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
124 goto Cleanup;
125 }
126
127 // Loop through all ports.
128 for (i = 0; i < dwPortCount; i++)
129 {
130 // Allocate memory for a new LOCALMON_PORT structure and its name.
131 pPort = DllAllocSplMem(sizeof(LOCALMON_PORT) + (cchMaxPortName + 1) * sizeof(WCHAR));
132 if (!pPort)
133 {
134 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
135 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
136 goto Cleanup;
137 }
138
139 pPort->hFile = INVALID_HANDLE_VALUE;
140 pPort->pwszPortName = (PWSTR)((PBYTE)pPort + sizeof(LOCALMON_PORT));
141
142 // Get the port name.
143 cchPortName = cchMaxPortName + 1;
144 dwErrorCode = (DWORD)RegEnumValueW(hKey, i, pPort->pwszPortName, &cchPortName, NULL, NULL, NULL, NULL);
145 if (dwErrorCode != ERROR_SUCCESS)
146 {
147 ERR("RegEnumValueW failed with status %lu!\n", dwErrorCode);
148 goto Cleanup;
149 }
150
151 // This Port Monitor supports COM, FILE and LPT ports. Skip all others.
152 if (_wcsnicmp(pPort->pwszPortName, L"COM", 3) != 0 && _wcsicmp(pPort->pwszPortName, L"FILE:") != 0 && _wcsnicmp(pPort->pwszPortName, L"LPT", 3) != 0)
153 {
154 DllFreeSplMem(pPort);
155 continue;
156 }
157
158 // Add it to the list.
159 InsertTailList(&pLocalmon->Ports, &pPort->Entry);
160
161 // Don't let the cleanup routine free this.
162 pPort = NULL;
163 }
164
165 // Return our handle and the Print Monitor functions.
166 *phMonitor = (HANDLE)pLocalmon;
167 pReturnValue = &_MonitorFunctions;
168 dwErrorCode = ERROR_SUCCESS;
169
170 Cleanup:
171 if (pPort)
172 DllFreeSplMem(pPort);
173
174 SetLastError(dwErrorCode);
175 return pReturnValue;
176 }