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
11 LIST_ENTRY PrintMonitorList;
12
13 // Local Constants
14 static DWORD dwMonitorInfo1Offsets[] = {
15 FIELD_OFFSET(MONITOR_INFO_1W, pName),
16 MAXDWORD
17 };
18
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),
23 MAXDWORD
24 };
25
26
27 PLOCAL_PRINT_MONITOR
FindPrintMonitor(PCWSTR pwszName)28 FindPrintMonitor(PCWSTR pwszName)
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
CreateKey(HANDLE hcKey,LPCWSTR pszSubKey,DWORD dwOptions,REGSAM samDesired,PSECURITY_ATTRIBUTES pSecurityAttributes,PHANDLE phckResult,PDWORD pdwDisposition,HANDLE hSpooler)49 static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions, REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes, PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
50 {
51 FIXME("stub\n");
52 return ERROR_CALL_NOT_IMPLEMENTED;
53 }
54
OpenKey(HANDLE hcKey,LPCWSTR pszSubKey,REGSAM samDesired,PHANDLE phkResult,HANDLE hSpooler)55 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired, PHANDLE phkResult, HANDLE hSpooler)
56 {
57 FIXME("stub\n");
58 return ERROR_CALL_NOT_IMPLEMENTED;
59 }
60
CloseKey(HANDLE hcKey,HANDLE hSpooler)61 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
62 {
63 FIXME("stub\n");
64 return ERROR_CALL_NOT_IMPLEMENTED;
65 }
66
DeleteKey(HANDLE hcKey,LPCWSTR pszSubKey,HANDLE hSpooler)67 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
68 {
69 FIXME("stub\n");
70 return ERROR_CALL_NOT_IMPLEMENTED;
71 }
72
EnumKey(HANDLE hcKey,DWORD dwIndex,LPWSTR pszName,PDWORD pcchName,PFILETIME pftLastWriteTime,HANDLE hSpooler)73 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName, PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
74 {
75 FIXME("stub\n");
76 return ERROR_CALL_NOT_IMPLEMENTED;
77 }
78
QueryInfoKey(HANDLE hcKey,PDWORD pcSubKeys,PDWORD pcbKey,PDWORD pcValues,PDWORD pcbValue,PDWORD pcbData,PDWORD pcbSecurityDescriptor,PFILETIME pftLastWriteTime,HANDLE hSpooler)79 static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey, PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData, PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
80 HANDLE hSpooler)
81 {
82 FIXME("stub\n");
83 return ERROR_CALL_NOT_IMPLEMENTED;
84 }
85
SetValue(HANDLE hcKey,LPCWSTR pszValue,DWORD dwType,const BYTE * pData,DWORD cbData,HANDLE hSpooler)86 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType, const BYTE* pData, DWORD cbData, HANDLE hSpooler)
87 {
88 FIXME("stub\n");
89 return ERROR_CALL_NOT_IMPLEMENTED;
90 }
91
DeleteValue(HANDLE hcKey,LPCWSTR pszValue,HANDLE hSpooler)92 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
93 {
94 FIXME("stub\n");
95 return ERROR_CALL_NOT_IMPLEMENTED;
96 }
97
EnumValue(HANDLE hcKey,DWORD dwIndex,LPWSTR pszValue,PDWORD pcbValue,PDWORD pType,PBYTE pData,PDWORD pcbData,HANDLE hSpooler)98 static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue, PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
99 {
100 FIXME("stub\n");
101 return ERROR_CALL_NOT_IMPLEMENTED;
102 }
103
QueryValue(HANDLE hcKey,LPCWSTR pszValue,PDWORD pType,PBYTE pData,PDWORD pcbData,HANDLE hSpooler)104 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
105 {
106 FIXME("stub\n");
107 return ERROR_CALL_NOT_IMPLEMENTED;
108 }
109
110 static MONITORREG MonReg =
111 {
112 sizeof(MONITORREG),
113 CreateKey,
114 OpenKey,
115 CloseKey,
116 DeleteKey,
117 EnumKey,
118 QueryInfoKey,
119 SetValue,
120 DeleteValue,
121 EnumValue,
122 QueryValue
123 };
124
125 BOOL
InitializePrintMonitorList(void)126 InitializePrintMonitorList(void)
127 {
128 const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors";
129 const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
130
131 DWORD cchMaxSubKey;
132 DWORD cchPrintMonitorName;
133 DWORD dwErrorCode;
134 DWORD dwSubKeys;
135 DWORD i;
136 HINSTANCE hinstPrintMonitor = NULL;
137 HKEY hKey = NULL;
138 HKEY hSubKey = NULL;
139 MONITORINIT MonitorInit;
140 PInitializePrintMonitor pfnInitializePrintMonitor;
141 PInitializePrintMonitor2 pfnInitializePrintMonitor2;
142 PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
143 PWSTR pwszRegistryPath = NULL;
144
145 TRACE("InitializePrintMonitorList()\n");
146
147 // Initialize an empty list for our Print Monitors.
148 InitializeListHead(&PrintMonitorList);
149
150 // Open the key containing Print Monitors.
151 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszMonitorsPath, 0, KEY_READ, &hKey);
152 if (dwErrorCode != ERROR_SUCCESS)
153 {
154 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
155 goto Cleanup;
156 }
157
158 // Get the number of Print Providers and maximum sub key length.
159 dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
160 if (dwErrorCode != ERROR_SUCCESS)
161 {
162 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
163 goto Cleanup;
164 }
165
166 // Loop through all available Print Providers.
167 for (i = 0; i < dwSubKeys; i++)
168 {
169 // Cleanup tasks from the previous run
170 if (hSubKey)
171 {
172 RegCloseKey(hSubKey);
173 hSubKey = NULL;
174 }
175
176 if (pwszRegistryPath)
177 {
178 DllFreeSplMem(pwszRegistryPath);
179 pwszRegistryPath = NULL;
180 }
181
182 if (pPrintMonitor)
183 {
184 if (pPrintMonitor->pwszFileName)
185 DllFreeSplMem(pPrintMonitor->pwszFileName);
186
187 if (pPrintMonitor->pwszName)
188 DllFreeSplMem(pPrintMonitor->pwszName);
189
190 DllFreeSplMem(pPrintMonitor);
191 pPrintMonitor = NULL;
192 }
193
194 // Create a new LOCAL_PRINT_MONITOR structure for it.
195 pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
196 if (!pPrintMonitor)
197 {
198 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
199 ERR("DllAllocSplMem failed!\n");
200 goto Cleanup;
201 }
202
203 memset( pPrintMonitor, 0, sizeof(LOCAL_PRINT_MONITOR));
204
205 // Allocate memory for the Print Monitor Name.
206 pPrintMonitor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
207 if (!pPrintMonitor->pwszName)
208 {
209 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
210 ERR("DllAllocSplMem failed!\n");
211 goto Cleanup;
212 }
213
214 // Get the name of this Print Monitor.
215 cchPrintMonitorName = cchMaxSubKey + 1;
216 dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pPrintMonitor->pwszName, &cchPrintMonitorName, NULL, NULL, NULL, NULL);
217 if (dwErrorCode != ERROR_SUCCESS)
218 {
219 ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
220 continue;
221 }
222
223 // Open this Print Monitor's registry key.
224 dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pPrintMonitor->pwszName, 0, KEY_READ, &hSubKey);
225 if (dwErrorCode != ERROR_SUCCESS)
226 {
227 ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pPrintMonitor->pwszName, dwErrorCode);
228 continue;
229 }
230
231 // Get the file name of the Print Monitor.
232 pPrintMonitor->pwszFileName = AllocAndRegQueryWSZ(hSubKey, L"Driver");
233 if (!pPrintMonitor->pwszFileName)
234 continue;
235
236 // Try to load it.
237 hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
238 if (!hinstPrintMonitor)
239 {
240 ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
241 continue;
242 }
243
244 pPrintMonitor->hModule = hinstPrintMonitor;
245
246 // Try to find a Level 2 initialization routine first.
247 pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
248 if (pfnInitializePrintMonitor2)
249 {
250 // Prepare a MONITORINIT structure.
251 MonitorInit.cbSize = sizeof(MONITORINIT);
252 MonitorInit.bLocal = TRUE;
253
254 // TODO: Fill the other fields.
255 MonitorInit.hckRegistryRoot = hKey;
256 MonitorInit.pMonitorReg = &MonReg;
257
258 // Call the Level 2 initialization routine.
259 pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
260 if (!pPrintMonitor->pMonitor)
261 {
262 ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
263 continue;
264 }
265 FIXME("InitializePrintMonitor2 loaded.\n");
266 pPrintMonitor->bIsLevel2 = TRUE;
267 }
268 else
269 {
270 // Try to find a Level 1 initialization routine then.
271 pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
272 if (pfnInitializePrintMonitor)
273 {
274 // Construct the registry path.
275 pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
276 if (!pwszRegistryPath)
277 {
278 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
279 ERR("DllAllocSplMem failed!\n");
280 goto Cleanup;
281 }
282
283 CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
284 pwszRegistryPath[cchMonitorsPath] = L'\\';
285 CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
286
287 // Call the Level 1 initialization routine.
288 pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
289 if (!pPrintMonitor->pMonitor)
290 {
291 ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
292 continue;
293 }
294 }
295 else
296 {
297 ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
298 continue;
299 }
300 }
301
302 // Add this Print Monitor to the list.
303 InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
304 FIXME("InitializePrintMonitorList Handle %p\n",pPrintMonitor->hMonitor);
305 pPrintMonitor->refcount++;
306
307 // Don't let the cleanup routine free this.
308 pPrintMonitor = NULL;
309 }
310
311 dwErrorCode = ERROR_SUCCESS;
312
313 Cleanup:
314 // Inside the loop
315 if (hSubKey)
316 RegCloseKey(hSubKey);
317
318 if (pwszRegistryPath)
319 DllFreeSplMem(pwszRegistryPath);
320
321 if (pPrintMonitor)
322 {
323 if (pPrintMonitor->pwszFileName)
324 DllFreeSplMem(pPrintMonitor->pwszFileName);
325
326 if (pPrintMonitor->pwszName)
327 DllFreeSplMem(pPrintMonitor->pwszName);
328
329 DllFreeSplMem(pPrintMonitor);
330 }
331
332 // Outside the loop
333 if (hKey)
334 RegCloseKey(hKey);
335
336 SetLastError(dwErrorCode);
337 return (dwErrorCode == ERROR_SUCCESS);
338 }
339
340
341 static void
_LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor,PMONITOR_INFO_1W * ppMonitorInfo,PBYTE * ppMonitorInfoEnd,PDWORD pcbNeeded)342 _LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_1W* ppMonitorInfo, PBYTE* ppMonitorInfoEnd, PDWORD pcbNeeded)
343 {
344 DWORD cbMonitorName;
345 PCWSTR pwszStrings[1];
346
347 // Calculate the string lengths.
348 if (!ppMonitorInfo)
349 {
350 cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
351
352 *pcbNeeded += sizeof(MONITOR_INFO_1W) + cbMonitorName;
353 return;
354 }
355
356 // Set the pName field.
357 pwszStrings[0] = pPrintMonitor->pwszName;
358
359 // Copy the structure and advance to the next one in the output buffer.
360 *ppMonitorInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppMonitorInfo), dwMonitorInfo1Offsets, *ppMonitorInfoEnd);
361 (*ppMonitorInfo)++;
362 }
363
364 static void
_LocalGetMonitorLevel2(PLOCAL_PRINT_MONITOR pPrintMonitor,PMONITOR_INFO_2W * ppMonitorInfo,PBYTE * ppMonitorInfoEnd,PDWORD pcbNeeded)365 _LocalGetMonitorLevel2(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_2W* ppMonitorInfo, PBYTE* ppMonitorInfoEnd, PDWORD pcbNeeded)
366 {
367 DWORD cbFileName;
368 DWORD cbMonitorName;
369 PCWSTR pwszStrings[3];
370
371 // Calculate the string lengths.
372 if (!ppMonitorInfo)
373 {
374 cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
375 cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
376
377 *pcbNeeded += sizeof(MONITOR_INFO_2W) + cbMonitorName + cbCurrentEnvironment + cbFileName;
378 return;
379 }
380
381 // Set the pName field.
382 pwszStrings[0] = pPrintMonitor->pwszName;
383
384 // Set the pEnvironment field.
385 pwszStrings[1] = (PWSTR)wszCurrentEnvironment;
386
387 // Set the pDLLName field.
388 pwszStrings[2] = pPrintMonitor->pwszFileName;
389
390 // Copy the structure and advance to the next one in the output buffer.
391 *ppMonitorInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppMonitorInfo), dwMonitorInfo2Offsets, *ppMonitorInfoEnd);
392 (*ppMonitorInfo)++;
393 }
394
395 BOOL WINAPI
LocalEnumMonitors(PWSTR pName,DWORD Level,PBYTE pMonitors,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)396 LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
397 {
398 DWORD dwErrorCode;
399 PBYTE pMonitorInfoEnd;
400 PLIST_ENTRY pEntry;
401 PLOCAL_PRINT_MONITOR pPrintMonitor;
402
403 TRACE("LocalEnumMonitors(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
404
405 // Sanity checks.
406 if (Level > 2)
407 {
408 dwErrorCode = ERROR_INVALID_LEVEL;
409 goto Cleanup;
410 }
411
412 // Begin counting.
413 *pcbNeeded = 0;
414 *pcReturned = 0;
415
416 // Count the required buffer size and the number of monitors.
417 for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
418 {
419 pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
420
421 if (Level == 1)
422 _LocalGetMonitorLevel1(pPrintMonitor, NULL, NULL, pcbNeeded);
423 else if (Level == 2)
424 _LocalGetMonitorLevel2(pPrintMonitor, NULL, NULL, pcbNeeded);
425 }
426
427 // Check if the supplied buffer is large enough.
428 if (cbBuf < *pcbNeeded)
429 {
430 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
431 goto Cleanup;
432 }
433
434 // Copy over the Monitor information.
435 pMonitorInfoEnd = &pMonitors[*pcbNeeded];
436
437 for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
438 {
439 pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
440
441 if (Level == 1)
442 _LocalGetMonitorLevel1(pPrintMonitor, (PMONITOR_INFO_1W*)&pMonitors, &pMonitorInfoEnd, NULL);
443 else if (Level == 2)
444 _LocalGetMonitorLevel2(pPrintMonitor, (PMONITOR_INFO_2W*)&pMonitors, &pMonitorInfoEnd, NULL);
445
446 (*pcReturned)++;
447 }
448
449 dwErrorCode = ERROR_SUCCESS;
450
451 Cleanup:
452 SetLastError(dwErrorCode);
453 return (dwErrorCode == ERROR_SUCCESS);
454 }
455
456 BOOL
AddPrintMonitorList(LPCWSTR pName,LPWSTR DllName)457 AddPrintMonitorList( LPCWSTR pName, LPWSTR DllName )
458 {
459 const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\";
460 const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
461
462 WCHAR wszRegRoot[MAX_PATH] = {0};
463
464 DWORD cchPrintMonitorName;
465 DWORD dwErrorCode;
466 HINSTANCE hinstPrintMonitor = NULL;
467 HKEY hKey = NULL;
468 MONITORINIT MonitorInit;
469 PInitializePrintMonitor pfnInitializePrintMonitor;
470 PInitializePrintMonitor2 pfnInitializePrintMonitor2;
471 PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
472 PWSTR pwszRegistryPath = NULL;
473
474 FIXME("AddPrintMonitorList( %S, %S)\n",pName, DllName);
475
476 StringCbCopyW(wszRegRoot, sizeof(wszRegRoot), wszMonitorsPath);
477 StringCbCatW(wszRegRoot, sizeof(wszRegRoot), pName);
478
479 // Open the key containing Print Monitors.
480 dwErrorCode = (DWORD)RegOpenKeyW( HKEY_LOCAL_MACHINE, wszRegRoot, &hKey );
481 if (dwErrorCode != ERROR_SUCCESS)
482 {
483 ERR("RegOpenKeyExW %S failed with status %lu!\n", wszRegRoot, dwErrorCode);
484 goto Cleanup;
485 }
486
487 // Create a new LOCAL_PRINT_MONITOR structure for it.
488 pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
489 if (!pPrintMonitor)
490 {
491 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
492 ERR("DllAllocSplMem failed!\n");
493 goto Cleanup;
494 }
495
496 memset( pPrintMonitor, 0, sizeof(LOCAL_PRINT_MONITOR));
497
498 // Allocate memory for the Print Monitor Name.
499 pPrintMonitor->pwszName = AllocSplStr( pName );
500 if (!pPrintMonitor->pwszName)
501 {
502 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
503 ERR("DllAllocSplMem failed!\n");
504 goto Cleanup;
505 }
506
507 cchPrintMonitorName = wcslen(pPrintMonitor->pwszName);
508
509 if ( DllName == NULL )
510 {
511 DWORD namesize;
512
513 dwErrorCode = RegQueryValueExW( hKey, L"Driver", NULL, NULL, NULL, &namesize );
514
515 if ( dwErrorCode == ERROR_SUCCESS )
516 {
517 DllName = DllAllocSplMem(namesize);
518
519 RegQueryValueExW( hKey, L"Driver", NULL, NULL, (LPBYTE)DllName, &namesize );
520
521 pPrintMonitor->pwszFileName = DllName;
522 }
523 else
524 {
525 ERR("DllName not found\n");
526 goto Cleanup;
527 }
528 }
529 else
530 {
531 pPrintMonitor->pwszFileName = AllocSplStr( DllName );
532 }
533
534 // Try to load it.
535 hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
536 if (!hinstPrintMonitor)
537 {
538 ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
539 dwErrorCode = GetLastError();
540 goto Cleanup;
541 }
542
543 pPrintMonitor->hModule = hinstPrintMonitor;
544
545 // Try to find a Level 2 initialization routine first.
546 pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
547 if (pfnInitializePrintMonitor2)
548 {
549 // Prepare a MONITORINIT structure.
550 MonitorInit.cbSize = sizeof(MONITORINIT);
551 MonitorInit.bLocal = TRUE;
552
553 // TODO: Fill the other fields.
554 MonitorInit.hckRegistryRoot = hKey;
555 MonitorInit.pMonitorReg = &MonReg;
556
557 // Call the Level 2 initialization routine.
558 pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
559 if (!pPrintMonitor->pMonitor)
560 {
561 ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
562 goto Cleanup;
563 }
564
565 pPrintMonitor->bIsLevel2 = TRUE;
566 }
567 else
568 {
569 // Try to find a Level 1 initialization routine then.
570 pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
571 if (pfnInitializePrintMonitor)
572 {
573 // Construct the registry path.
574 pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
575 if (!pwszRegistryPath)
576 {
577 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
578 ERR("DllAllocSplMem failed!\n");
579 goto Cleanup;
580 }
581
582 CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
583 pwszRegistryPath[cchMonitorsPath] = L'\\';
584 CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
585
586 // Call the Level 1 initialization routine.
587 pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
588 if (!pPrintMonitor->pMonitor)
589 {
590 ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
591 goto Cleanup;
592 }
593 }
594 else
595 {
596 ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
597 dwErrorCode = ERROR_PROC_NOT_FOUND;
598 goto Cleanup;
599 }
600 }
601 // Add this Print Monitor to the list.
602 InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
603 FIXME("AddPrintMonitorList Handle %p\n",pPrintMonitor->hMonitor);
604
605 pPrintMonitor->refcount++;
606
607 // Don't let the cleanup routine free this.
608 pPrintMonitor = NULL;
609
610 dwErrorCode = ERROR_SUCCESS;
611
612 Cleanup:
613 if (pwszRegistryPath)
614 DllFreeSplMem(pwszRegistryPath);
615
616 if (pPrintMonitor)
617 {
618 if (pPrintMonitor->pwszFileName)
619 DllFreeSplMem(pPrintMonitor->pwszFileName);
620
621 if (pPrintMonitor->pwszName)
622 DllFreeSplMem(pPrintMonitor->pwszName);
623
624 DllFreeSplMem(pPrintMonitor);
625 }
626
627 // Outside the loop
628 if (hKey)
629 RegCloseKey(hKey);
630
631 SetLastError(dwErrorCode);
632 return (dwErrorCode == ERROR_SUCCESS);
633 }
634
635 BOOL WINAPI
LocalAddMonitor(PWSTR pName,DWORD Level,PBYTE pMonitors)636 LocalAddMonitor(PWSTR pName, DWORD Level, PBYTE pMonitors)
637 {
638 PPRINTENV_T env;
639 LPMONITOR_INFO_2W mi2w;
640 HKEY hroot = NULL;
641 HKEY hentry = NULL;
642 DWORD disposition;
643 BOOL res = FALSE;
644 const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\";
645
646 mi2w = (LPMONITOR_INFO_2W) pMonitors;
647
648 FIXME("LocalAddMonitor(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
649 debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
650
651 if (copy_servername_from_name(pName, NULL))
652 {
653 FIXME("server %s not supported\n", debugstr_w(pName));
654 SetLastError(ERROR_ACCESS_DENIED);
655 return FALSE;
656 }
657
658 if (!mi2w->pName || (!mi2w->pName[0]) )
659 {
660 FIXME("pName not valid : %s\n", debugstr_w(mi2w->pName));
661 SetLastError(ERROR_INVALID_PARAMETER);
662 return FALSE;
663 }
664
665 env = validate_envW(mi2w->pEnvironment);
666 if (!env)
667 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
668
669 if (!mi2w->pDLLName || (!mi2w->pDLLName[0]) )
670 {
671 FIXME("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
672 SetLastError(ERROR_INVALID_PARAMETER);
673 return FALSE;
674 }
675
676 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, wszMonitorsPath, &hroot) != ERROR_SUCCESS) {
677 ERR("unable to create key %s\n", debugstr_w(wszMonitorsPath));
678 return FALSE;
679 }
680
681 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry, &disposition) == ERROR_SUCCESS)
682 {
683 /* Some installers set options for the port before calling AddMonitor.
684 We query the "Driver" entry to verify that the monitor is installed,
685 before we return an error.
686 When a user installs two print monitors at the same time with the
687 same name, a race condition is possible but silently ignored. */
688
689 DWORD namesize = 0;
690
691 if ((disposition == REG_OPENED_EXISTING_KEY) &&
692 (RegQueryValueExW(hentry, L"Driver", NULL, NULL, NULL, &namesize) == ERROR_SUCCESS))
693 {
694 FIXME("monitor %s already exists\n", debugstr_w(mi2w->pName));
695 /* 9x use ERROR_ALREADY_EXISTS */
696 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
697 }
698 else
699 {
700 INT len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
701
702 res = (RegSetValueExW(hentry, L"Driver", 0, REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
703
704 /* Load and initialize the monitor. SetLastError() is called on failure */
705
706 res = AddPrintMonitorList( mi2w->pName, mi2w->pDLLName );
707
708 if ( !res )
709 {
710 RegDeleteKeyW(hroot, mi2w->pName);
711 }
712 else
713 SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
714 }
715
716 RegCloseKey(hentry);
717 }
718
719 RegCloseKey(hroot);
720 return res;
721 }
722
723 BOOL WINAPI
LocalDeleteMonitor(PWSTR pName,PWSTR pEnvironment,PWSTR pMonitorName)724 LocalDeleteMonitor(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
725 {
726 HKEY hroot = NULL;
727 LONG lres;
728 PLOCAL_PRINT_MONITOR pPrintMonitor;
729 const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\";
730
731 FIXME("LocalDeleteMonitor(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
732 debugstr_w(pMonitorName));
733
734 lres = copy_servername_from_name(pName, NULL);
735 if (lres)
736 {
737 FIXME("server %s not supported\n", debugstr_w(pName));
738 SetLastError(ERROR_INVALID_NAME);
739 return FALSE;
740 }
741
742 /* pEnvironment is ignored in Windows for the local Computer */
743 if (!pMonitorName || !pMonitorName[0])
744 {
745 ERR("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
746 SetLastError(ERROR_INVALID_PARAMETER);
747 return FALSE;
748 }
749
750 pPrintMonitor = FindPrintMonitor( pMonitorName );
751 if ( pPrintMonitor )
752 {
753 if ( pPrintMonitor->refcount ) pPrintMonitor->refcount--;
754
755 if ( pPrintMonitor->refcount == 0 )
756 { /* Unload the monitor if it's loaded */
757 RemoveEntryList(&pPrintMonitor->Entry);
758
759 if ( pPrintMonitor->bIsLevel2 )
760 {
761 PMONITOR2 pm2 = pPrintMonitor->pMonitor;
762 if ( pm2 && pm2->pfnShutdown )
763 {
764 pm2->pfnShutdown(pPrintMonitor->hMonitor);
765 }
766 }
767
768 if ( pPrintMonitor->hModule )
769 FreeLibrary(pPrintMonitor->hModule);
770
771 if (pPrintMonitor->pwszFileName)
772 DllFreeSplStr(pPrintMonitor->pwszFileName);
773
774 if (pPrintMonitor->pwszName)
775 DllFreeSplStr(pPrintMonitor->pwszName);
776
777 DllFreeSplMem(pPrintMonitor);
778 pPrintMonitor = NULL;
779 }
780 }
781 else
782 {
783 FIXME("Could not find %s\n", debugstr_w(pMonitorName));
784 }
785
786 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, wszMonitorsPath, &hroot) != ERROR_SUCCESS)
787 {
788 ERR("unable to create key %s\n", debugstr_w(wszMonitorsPath));
789 return FALSE;
790 }
791
792 if (RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS)
793 {
794 FIXME("%s deleted\n", debugstr_w(pMonitorName));
795 RegCloseKey(hroot);
796 return TRUE;
797 }
798
799 FIXME("%s does not exist\n", debugstr_w(pMonitorName));
800 RegCloseKey(hroot);
801
802 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
803 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
804 return FALSE;
805 }
806