ReactOS  0.4.12-dev-712-ge6be187
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.
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  PCWSTR 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  PCWSTR 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 }
LPMONITOR2(WINAPI * PInitializePrintMonitor2)(PMONITORINIT, PHANDLE)
Definition: precomp.h:51
const uint16_t * PCWSTR
Definition: typedefs.h:55
#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 DWORD
Definition: msvc.h:34
uint16_t * PWSTR
Definition: typedefs.h:54
#define _countof(array)
Definition: fontsub.cpp:30
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
#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)
struct _MONITOR_INFO_2W MONITOR_INFO_2W
const DWORD cbCurrentEnvironment
static DWORD dwMonitorInfo1Offsets[]
Definition: monitors.c:14
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
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(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
#define CopyMemory
Definition: winbase.h:1633
unsigned long DWORD
Definition: ntddk_ex.h:95
#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
LIST_ENTRY Entry
Definition: precomp.h:71
static const WCHAR L[]
Definition: oid.c:1250
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
LPMONITOREX(WINAPI * PInitializePrintMonitor)(PWSTR)
Definition: precomp.h:50
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
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