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)
11 LIST_ENTRY PrintMonitorList
;
14 static DWORD dwMonitorInfo1Offsets
[] = {
15 FIELD_OFFSET(MONITOR_INFO_1W
, pName
),
19 static DWORD dwMonitorInfo2Offsets
[] = {
20 FIELD_OFFSET(MONITOR_INFO_2W
, pName
),
21 FIELD_OFFSET(MONITOR_INFO_2W
, pEnvironment
),
22 FIELD_OFFSET(MONITOR_INFO_2W
, pDLLName
),
28 FindPrintMonitor(PCWSTR pwszName
)
31 PLOCAL_PRINT_MONITOR pPrintMonitor
;
33 TRACE("FindPrintMonitor(%S)\n", pwszName
);
38 for (pEntry
= PrintMonitorList
.Flink
; pEntry
!= &PrintMonitorList
; pEntry
= pEntry
->Flink
)
40 pPrintMonitor
= CONTAINING_RECORD(pEntry
, LOCAL_PRINT_MONITOR
, Entry
);
42 if (_wcsicmp(pPrintMonitor
->pwszName
, pwszName
) == 0)
50 InitializePrintMonitorList(void)
52 const WCHAR wszMonitorsPath
[] = L
"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors";
53 const DWORD cchMonitorsPath
= _countof(wszMonitorsPath
) - 1;
56 DWORD cchPrintMonitorName
;
60 HINSTANCE hinstPrintMonitor
= NULL
;
63 MONITORINIT MonitorInit
;
64 PInitializePrintMonitor pfnInitializePrintMonitor
;
65 PInitializePrintMonitor2 pfnInitializePrintMonitor2
;
66 PLOCAL_PRINT_MONITOR pPrintMonitor
= NULL
;
67 PWSTR pwszRegistryPath
= NULL
;
69 TRACE("InitializePrintMonitorList()\n");
71 // Initialize an empty list for our Print Monitors.
72 InitializeListHead(&PrintMonitorList
);
74 // Open the key containing Print Monitors.
75 dwErrorCode
= (DWORD
)RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszMonitorsPath
, 0, KEY_READ
, &hKey
);
76 if (dwErrorCode
!= ERROR_SUCCESS
)
78 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode
);
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
)
86 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode
);
90 // Loop through all available Print Providers.
91 for (i
= 0; i
< dwSubKeys
; i
++)
93 // Cleanup tasks from the previous run
100 if (pwszRegistryPath
)
102 DllFreeSplMem(pwszRegistryPath
);
103 pwszRegistryPath
= NULL
;
108 if (pPrintMonitor
->pwszFileName
)
109 DllFreeSplMem(pPrintMonitor
->pwszFileName
);
111 if (pPrintMonitor
->pwszName
)
112 DllFreeSplMem(pPrintMonitor
->pwszName
);
114 DllFreeSplMem(pPrintMonitor
);
115 pPrintMonitor
= NULL
;
118 // Create a new LOCAL_PRINT_MONITOR structure for it.
119 pPrintMonitor
= DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR
));
122 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
123 ERR("DllAllocSplMem failed!\n");
127 // Allocate memory for the Print Monitor Name.
128 pPrintMonitor
->pwszName
= DllAllocSplMem((cchMaxSubKey
+ 1) * sizeof(WCHAR
));
129 if (!pPrintMonitor
->pwszName
)
131 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
132 ERR("DllAllocSplMem failed!\n");
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
)
141 ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i
, dwErrorCode
);
145 // Open this Print Monitor's registry key.
146 dwErrorCode
= (DWORD
)RegOpenKeyExW(hKey
, pPrintMonitor
->pwszName
, 0, KEY_READ
, &hSubKey
);
147 if (dwErrorCode
!= ERROR_SUCCESS
)
149 ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pPrintMonitor
->pwszName
, dwErrorCode
);
153 // Get the file name of the Print Monitor.
154 pPrintMonitor
->pwszFileName
= AllocAndRegQueryWSZ(hSubKey
, L
"Driver");
155 if (!pPrintMonitor
->pwszFileName
)
159 hinstPrintMonitor
= LoadLibraryW(pPrintMonitor
->pwszFileName
);
160 if (!hinstPrintMonitor
)
162 ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor
->pwszFileName
, GetLastError());
166 // Try to find a Level 2 initialization routine first.
167 pfnInitializePrintMonitor2
= (PInitializePrintMonitor2
)GetProcAddress(hinstPrintMonitor
, "InitializePrintMonitor2");
168 if (pfnInitializePrintMonitor2
)
170 // Prepare a MONITORINIT structure.
171 MonitorInit
.cbSize
= sizeof(MONITORINIT
);
172 MonitorInit
.bLocal
= TRUE
;
174 // TODO: Fill the other fields.
176 // Call the Level 2 initialization routine.
177 pPrintMonitor
->pMonitor
= (PMONITOR2
)pfnInitializePrintMonitor2(&MonitorInit
, &pPrintMonitor
->hMonitor
);
178 if (!pPrintMonitor
->pMonitor
)
180 ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor
->pwszFileName
, GetLastError());
184 pPrintMonitor
->bIsLevel2
= TRUE
;
188 // Try to find a Level 1 initialization routine then.
189 pfnInitializePrintMonitor
= (PInitializePrintMonitor
)GetProcAddress(hinstPrintMonitor
, "InitializePrintMonitor");
190 if (pfnInitializePrintMonitor
)
192 // Construct the registry path.
193 pwszRegistryPath
= DllAllocSplMem((cchMonitorsPath
+ 1 + cchPrintMonitorName
+ 1) * sizeof(WCHAR
));
194 if (!pwszRegistryPath
)
196 dwErrorCode
= ERROR_NOT_ENOUGH_MEMORY
;
197 ERR("DllAllocSplMem failed!\n");
201 CopyMemory(pwszRegistryPath
, wszMonitorsPath
, cchMonitorsPath
* sizeof(WCHAR
));
202 pwszRegistryPath
[cchMonitorsPath
] = L
'\\';
203 CopyMemory(&pwszRegistryPath
[cchMonitorsPath
+ 1], pPrintMonitor
->pwszName
, (cchPrintMonitorName
+ 1) * sizeof(WCHAR
));
205 // Call the Level 1 initialization routine.
206 pPrintMonitor
->pMonitor
= (LPMONITOREX
)pfnInitializePrintMonitor(pwszRegistryPath
);
207 if (!pPrintMonitor
->pMonitor
)
209 ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor
->pwszFileName
, GetLastError());
215 ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor
->pwszFileName
);
220 // Add this Print Monitor to the list.
221 InsertTailList(&PrintMonitorList
, &pPrintMonitor
->Entry
);
223 // Don't let the cleanup routine free this.
224 pPrintMonitor
= NULL
;
227 dwErrorCode
= ERROR_SUCCESS
;
232 RegCloseKey(hSubKey
);
234 if (pwszRegistryPath
)
235 DllFreeSplMem(pwszRegistryPath
);
239 if (pPrintMonitor
->pwszFileName
)
240 DllFreeSplMem(pPrintMonitor
->pwszFileName
);
242 if (pPrintMonitor
->pwszName
)
243 DllFreeSplMem(pPrintMonitor
->pwszName
);
245 DllFreeSplMem(pPrintMonitor
);
252 SetLastError(dwErrorCode
);
253 return (dwErrorCode
== ERROR_SUCCESS
);
257 _LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor
, PMONITOR_INFO_1W
* ppMonitorInfo
, PBYTE
* ppMonitorInfoEnd
, PDWORD pcbNeeded
)
260 PWSTR pwszStrings
[1];
262 // Calculate the string lengths.
265 cbMonitorName
= (wcslen(pPrintMonitor
->pwszName
) + 1) * sizeof(WCHAR
);
267 *pcbNeeded
+= sizeof(MONITOR_INFO_1W
) + cbMonitorName
;
271 // Set the pName field.
272 pwszStrings
[0] = pPrintMonitor
->pwszName
;
274 // Copy the structure and advance to the next one in the output buffer.
275 *ppMonitorInfoEnd
= PackStrings(pwszStrings
, (PBYTE
)(*ppMonitorInfo
), dwMonitorInfo1Offsets
, *ppMonitorInfoEnd
);
280 _LocalGetMonitorLevel2(PLOCAL_PRINT_MONITOR pPrintMonitor
, PMONITOR_INFO_2W
* ppMonitorInfo
, PBYTE
* ppMonitorInfoEnd
, PDWORD pcbNeeded
)
284 PWSTR pwszStrings
[3];
286 // Calculate the string lengths.
289 cbMonitorName
= (wcslen(pPrintMonitor
->pwszName
) + 1) * sizeof(WCHAR
);
290 cbFileName
= (wcslen(pPrintMonitor
->pwszFileName
) + 1) * sizeof(WCHAR
);
292 *pcbNeeded
+= sizeof(MONITOR_INFO_2W
) + cbMonitorName
+ cbCurrentEnvironment
+ cbFileName
;
296 // Set the pName field.
297 pwszStrings
[0] = pPrintMonitor
->pwszName
;
299 // Set the pEnvironment field.
300 pwszStrings
[1] = (PWSTR
)wszCurrentEnvironment
;
302 // Set the pDLLName field.
303 pwszStrings
[2] = pPrintMonitor
->pwszFileName
;
305 // Copy the structure and advance to the next one in the output buffer.
306 *ppMonitorInfoEnd
= PackStrings(pwszStrings
, (PBYTE
)(*ppMonitorInfo
), dwMonitorInfo2Offsets
, *ppMonitorInfoEnd
);
311 LocalEnumMonitors(PWSTR pName
, DWORD Level
, PBYTE pMonitors
, DWORD cbBuf
, PDWORD pcbNeeded
, PDWORD pcReturned
)
314 PBYTE pMonitorInfoEnd
;
316 PLOCAL_PRINT_MONITOR pPrintMonitor
;
318 TRACE("LocalEnumMonitors(%S, %lu, %p, %lu, %p, %p)\n", pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
323 dwErrorCode
= ERROR_INVALID_LEVEL
;
331 // Count the required buffer size and the number of monitors.
332 for (pEntry
= PrintMonitorList
.Flink
; pEntry
!= &PrintMonitorList
; pEntry
= pEntry
->Flink
)
334 pPrintMonitor
= CONTAINING_RECORD(pEntry
, LOCAL_PRINT_MONITOR
, Entry
);
337 _LocalGetMonitorLevel1(pPrintMonitor
, NULL
, NULL
, pcbNeeded
);
339 _LocalGetMonitorLevel2(pPrintMonitor
, NULL
, NULL
, pcbNeeded
);
342 // Check if the supplied buffer is large enough.
343 if (cbBuf
< *pcbNeeded
)
345 dwErrorCode
= ERROR_INSUFFICIENT_BUFFER
;
349 // Copy over the Monitor information.
350 pMonitorInfoEnd
= &pMonitors
[*pcbNeeded
];
352 for (pEntry
= PrintMonitorList
.Flink
; pEntry
!= &PrintMonitorList
; pEntry
= pEntry
->Flink
)
354 pPrintMonitor
= CONTAINING_RECORD(pEntry
, LOCAL_PRINT_MONITOR
, Entry
);
357 _LocalGetMonitorLevel1(pPrintMonitor
, (PMONITOR_INFO_1W
*)&pMonitors
, &pMonitorInfoEnd
, NULL
);
359 _LocalGetMonitorLevel2(pPrintMonitor
, (PMONITOR_INFO_2W
*)&pMonitors
, &pMonitorInfoEnd
, NULL
);
364 dwErrorCode
= ERROR_SUCCESS
;
367 SetLastError(dwErrorCode
);
368 return (dwErrorCode
== ERROR_SUCCESS
);