ReactOS  0.4.11-dev-791-gf6f1255
monitors.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Local Spooler
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Functions related to Print Monitors
5  * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 // Global Variables
12 
13 // Local Constants
16  MAXDWORD
17 };
18 
21  FIELD_OFFSET(MONITOR_INFO_2W, pEnvironment),
22  FIELD_OFFSET(MONITOR_INFO_2W, pDLLName),
23  MAXDWORD
24 };
25 
26 
29 {
30  PLIST_ENTRY pEntry;
31  PLOCAL_PRINT_MONITOR pPrintMonitor;
32 
33  TRACE("FindPrintMonitor(%S)\n", pwszName);
34 
35  if (!pwszName)
36  return NULL;
37 
38  for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
39  {
40  pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
41 
42  if (_wcsicmp(pPrintMonitor->pwszName, pwszName) == 0)
43  return pPrintMonitor;
44  }
45 
46  return NULL;
47 }
48 
49 BOOL
51 {
52  const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors";
53  const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
54 
55  DWORD cchMaxSubKey;
56  DWORD cchPrintMonitorName;
57  DWORD dwErrorCode;
58  DWORD dwSubKeys;
59  DWORD i;
60  HINSTANCE hinstPrintMonitor = NULL;
61  HKEY hKey = NULL;
62  HKEY hSubKey = NULL;
63  MONITORINIT MonitorInit;
64  PInitializePrintMonitor pfnInitializePrintMonitor;
65  PInitializePrintMonitor2 pfnInitializePrintMonitor2;
66  PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
67  PWSTR pwszRegistryPath = NULL;
68 
69  TRACE("InitializePrintMonitorList()\n");
70 
71  // Initialize an empty list for our Print Monitors.
72  InitializeListHead(&PrintMonitorList);
73 
74  // Open the key containing Print Monitors.
75  dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszMonitorsPath, 0, KEY_READ, &hKey);
76  if (dwErrorCode != ERROR_SUCCESS)
77  {
78  ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
79  goto Cleanup;
80  }
81 
82  // Get the number of Print Providers and maximum sub key length.
83  dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
84  if (dwErrorCode != ERROR_SUCCESS)
85  {
86  ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
87  goto Cleanup;
88  }
89 
90  // Loop through all available Print Providers.
91  for (i = 0; i < dwSubKeys; i++)
92  {
93  // Cleanup tasks from the previous run
94  if (hSubKey)
95  {
96  RegCloseKey(hSubKey);
97  hSubKey = NULL;
98  }
99 
100  if (pwszRegistryPath)
101  {
102  DllFreeSplMem(pwszRegistryPath);
103  pwszRegistryPath = NULL;
104  }
105 
106  if (pPrintMonitor)
107  {
108  if (pPrintMonitor->pwszFileName)
109  DllFreeSplMem(pPrintMonitor->pwszFileName);
110 
111  if (pPrintMonitor->pwszName)
112  DllFreeSplMem(pPrintMonitor->pwszName);
113 
114  DllFreeSplMem(pPrintMonitor);
115  pPrintMonitor = NULL;
116  }
117 
118  // Create a new LOCAL_PRINT_MONITOR structure for it.
119  pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
120  if (!pPrintMonitor)
121  {
122  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
123  ERR("DllAllocSplMem failed!\n");
124  goto Cleanup;
125  }
126 
127  // Allocate memory for the Print Monitor Name.
128  pPrintMonitor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
129  if (!pPrintMonitor->pwszName)
130  {
131  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
132  ERR("DllAllocSplMem failed!\n");
133  goto Cleanup;
134  }
135 
136  // Get the name of this Print Monitor.
137  cchPrintMonitorName = cchMaxSubKey + 1;
138  dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pPrintMonitor->pwszName, &cchPrintMonitorName, NULL, NULL, NULL, NULL);
139  if (dwErrorCode != ERROR_SUCCESS)
140  {
141  ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
142  continue;
143  }
144 
145  // Open this Print Monitor's registry key.
146  dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pPrintMonitor->pwszName, 0, KEY_READ, &hSubKey);
147  if (dwErrorCode != ERROR_SUCCESS)
148  {
149  ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pPrintMonitor->pwszName, dwErrorCode);
150  continue;
151  }
152 
153  // Get the file name of the Print Monitor.
154  pPrintMonitor->pwszFileName = AllocAndRegQueryWSZ(hSubKey, L"Driver");
155  if (!pPrintMonitor->pwszFileName)
156  continue;
157 
158  // Try to load it.
159  hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
160  if (!hinstPrintMonitor)
161  {
162  ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
163  continue;
164  }
165 
166  // Try to find a Level 2 initialization routine first.
167  pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
168  if (pfnInitializePrintMonitor2)
169  {
170  // Prepare a MONITORINIT structure.
171  MonitorInit.cbSize = sizeof(MONITORINIT);
172  MonitorInit.bLocal = TRUE;
173 
174  // TODO: Fill the other fields.
175 
176  // Call the Level 2 initialization routine.
177  pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
178  if (!pPrintMonitor->pMonitor)
179  {
180  ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
181  continue;
182  }
183 
184  pPrintMonitor->bIsLevel2 = TRUE;
185  }
186  else
187  {
188  // Try to find a Level 1 initialization routine then.
189  pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
190  if (pfnInitializePrintMonitor)
191  {
192  // Construct the registry path.
193  pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
194  if (!pwszRegistryPath)
195  {
196  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
197  ERR("DllAllocSplMem failed!\n");
198  goto Cleanup;
199  }
200 
201  CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
202  pwszRegistryPath[cchMonitorsPath] = L'\\';
203  CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
204 
205  // Call the Level 1 initialization routine.
206  pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
207  if (!pPrintMonitor->pMonitor)
208  {
209  ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
210  continue;
211  }
212  }
213  else
214  {
215  ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
216  continue;
217  }
218  }
219 
220  // Add this Print Monitor to the list.
221  InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
222 
223  // Don't let the cleanup routine free this.
224  pPrintMonitor = NULL;
225  }
226 
227  dwErrorCode = ERROR_SUCCESS;
228 
229 Cleanup:
230  // Inside the loop
231  if (hSubKey)
232  RegCloseKey(hSubKey);
233 
234  if (pwszRegistryPath)
235  DllFreeSplMem(pwszRegistryPath);
236 
237  if (pPrintMonitor)
238  {
239  if (pPrintMonitor->pwszFileName)
240  DllFreeSplMem(pPrintMonitor->pwszFileName);
241 
242  if (pPrintMonitor->pwszName)
243  DllFreeSplMem(pPrintMonitor->pwszName);
244 
245  DllFreeSplMem(pPrintMonitor);
246  }
247 
248  // Outside the loop
249  if (hKey)
250  RegCloseKey(hKey);
251 
252  SetLastError(dwErrorCode);
253  return (dwErrorCode == ERROR_SUCCESS);
254 }
255 
256 static void
257 _LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_1W* ppMonitorInfo, PBYTE* ppMonitorInfoEnd, PDWORD pcbNeeded)
258 {
259  DWORD cbMonitorName;
260  PWSTR pwszStrings[1];
261 
262  // Calculate the string lengths.
263  if (!ppMonitorInfo)
264  {
265  cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
266 
267  *pcbNeeded += sizeof(MONITOR_INFO_1W) + cbMonitorName;
268  return;
269  }
270 
271  // Set the pName field.
272  pwszStrings[0] = pPrintMonitor->pwszName;
273 
274  // Copy the structure and advance to the next one in the output buffer.
275  *ppMonitorInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppMonitorInfo), dwMonitorInfo1Offsets, *ppMonitorInfoEnd);
276  (*ppMonitorInfo)++;
277 }
278 
279 static void
280 _LocalGetMonitorLevel2(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_2W* ppMonitorInfo, PBYTE* ppMonitorInfoEnd, PDWORD pcbNeeded)
281 {
282  DWORD cbFileName;
283  DWORD cbMonitorName;
284  PWSTR pwszStrings[3];
285 
286  // Calculate the string lengths.
287  if (!ppMonitorInfo)
288  {
289  cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
290  cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
291 
292  *pcbNeeded += sizeof(MONITOR_INFO_2W) + cbMonitorName + cbCurrentEnvironment + cbFileName;
293  return;
294  }
295 
296  // Set the pName field.
297  pwszStrings[0] = pPrintMonitor->pwszName;
298 
299  // Set the pEnvironment field.
300  pwszStrings[1] = (PWSTR)wszCurrentEnvironment;
301 
302  // Set the pDLLName field.
303  pwszStrings[2] = pPrintMonitor->pwszFileName;
304 
305  // Copy the structure and advance to the next one in the output buffer.
306  *ppMonitorInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppMonitorInfo), dwMonitorInfo2Offsets, *ppMonitorInfoEnd);
307  (*ppMonitorInfo)++;
308 }
309 
310 BOOL WINAPI
312 {
313  DWORD dwErrorCode;
314  PBYTE pMonitorInfoEnd;
315  PLIST_ENTRY pEntry;
316  PLOCAL_PRINT_MONITOR pPrintMonitor;
317 
318  TRACE("LocalEnumMonitors(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
319 
320  // Sanity checks.
321  if (Level > 2)
322  {
323  dwErrorCode = ERROR_INVALID_LEVEL;
324  goto Cleanup;
325  }
326 
327  // Begin counting.
328  *pcbNeeded = 0;
329  *pcReturned = 0;
330 
331  // Count the required buffer size and the number of monitors.
332  for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
333  {
334  pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
335 
336  if (Level == 1)
337  _LocalGetMonitorLevel1(pPrintMonitor, NULL, NULL, pcbNeeded);
338  else if (Level == 2)
339  _LocalGetMonitorLevel2(pPrintMonitor, NULL, NULL, pcbNeeded);
340  }
341 
342  // Check if the supplied buffer is large enough.
343  if (cbBuf < *pcbNeeded)
344  {
345  dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
346  goto Cleanup;
347  }
348 
349  // Copy over the Monitor information.
350  pMonitorInfoEnd = &pMonitors[*pcbNeeded];
351 
352  for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
353  {
354  pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
355 
356  if (Level == 1)
357  _LocalGetMonitorLevel1(pPrintMonitor, (PMONITOR_INFO_1W*)&pMonitors, &pMonitorInfoEnd, NULL);
358  else if (Level == 2)
359  _LocalGetMonitorLevel2(pPrintMonitor, (PMONITOR_INFO_2W*)&pMonitors, &pMonitorInfoEnd, NULL);
360 
361  (*pcReturned)++;
362  }
363 
364  dwErrorCode = ERROR_SUCCESS;
365 
366 Cleanup:
367  SetLastError(dwErrorCode);
368  return (dwErrorCode == ERROR_SUCCESS);
369 }
#define TRUE
Definition: types.h:120
BOOL InitializePrintMonitorList(void)
Definition: monitors.c:50
#define ERROR_SUCCESS
Definition: deptool.c:10
#define KEY_READ
Definition: nt_native.h:1023
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define _countof(array)
Definition: fontsub.cpp:30
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
PVOID *typedef PWSTR
Definition: winlogon.h:66
LPMONITOR2(WINAPI * PInitializePrintMonitor2)(PMONITORINIT, PHANDLE)
Definition: precomp.h:51
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
#define InsertTailList(ListHead, Entry)
LPMONITOREX(WINAPI * PInitializePrintMonitor)(PWSTR)
Definition: precomp.h:50
#define DWORD
Definition: msvc.h:34
DWORD DWORD
Definition: winlogon.h:84
struct _MONITOR_INFO_2W MONITOR_INFO_2W
const DWORD cbCurrentEnvironment
static DWORD dwMonitorInfo1Offsets[]
Definition: monitors.c:14
GLenum GLclampf GLint i
Definition: glfuncs.h:14
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
static void _LocalGetMonitorLevel2(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_2W *ppMonitorInfo, PBYTE *ppMonitorInfoEnd, PDWORD pcbNeeded)
Definition: monitors.c:280
const WCHAR wszCurrentEnvironment[]
Definition: prtprocenv.h:11
#define LoadLibraryW(x)
Definition: compat.h:404
smooth NULL
Definition: ftsmooth.c:416
PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
Definition: tools.c:26
#define MAXDWORD
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
struct _MONITORINIT MONITORINIT
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: monitors.c:311
#define TRACE(s)
Definition: solgame.cpp:4
static LPSTR pName
Definition: security.c:75
unsigned int BOOL
Definition: ntddk_ex.h:94
static DWORD dwMonitorInfo2Offsets[]
Definition: monitors.c:19
PBYTE WINAPI PackStrings(PWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
HANDLE HKEY
Definition: registry.h:24
#define CopyMemory
Definition: winbase.h:1633
#define SetLastError(x)
Definition: compat.h:409
LONG WINAPI RegQueryInfoKeyW(HKEY hKey, LPWSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
Definition: reg.c:3704
HANDLE HINSTANCE
Definition: typedefs.h:75
LIST_ENTRY Entry
Definition: precomp.h:71
static const WCHAR L[]
Definition: oid.c:1087
Definition: typedefs.h:117
static const WCHAR Cleanup[]
Definition: register.c:80
#define WINAPI
Definition: msvc.h:20
DWORD cbSize
Definition: winsplp.h:746
#define ERR(fmt,...)
Definition: debug.h:109
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3827
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
DWORD * PDWORD
Definition: pedump.c:68
LIST_ENTRY PrintMonitorList
Definition: monitors.c:11
BOOL bLocal
Definition: winsplp.h:750
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3381
struct _MONITOR2 * PMONITOR2
#define GetProcAddress(x, y)
Definition: compat.h:410
LONG WINAPI RegEnumKeyExW(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPWSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: reg.c:2541
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
const uint16_t * PCWSTR
Definition: typedefs.h:55
PLOCAL_PRINT_MONITOR FindPrintMonitor(PCWSTR pwszName)
Definition: monitors.c:28
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
struct _MONITOR_INFO_1W MONITOR_INFO_1W
struct _MONITOREX * LPMONITOREX
BYTE * PBYTE
Definition: pedump.c:66
static void _LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_1W *ppMonitorInfo, PBYTE *ppMonitorInfoEnd, PDWORD pcbNeeded)
Definition: monitors.c:257
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
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)
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10