ReactOS  0.4.15-dev-1203-g0e5a4d5
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 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");
53 }
54 
55 static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired, PHANDLE phkResult, HANDLE hSpooler)
56 {
57  FIXME("stub\n");
59 }
60 
61 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
62 {
63  FIXME("stub\n");
65 }
66 
67 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
68 {
69  FIXME("stub\n");
71 }
72 
73 static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName, PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
74 {
75  FIXME("stub\n");
77 }
78 
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");
84 }
85 
86 static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType, const BYTE* pData, DWORD cbData, HANDLE hSpooler)
87 {
88  FIXME("stub\n");
90 }
91 
92 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
93 {
94  FIXME("stub\n");
96 }
97 
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");
102 }
103 
104 static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
105 {
106  FIXME("stub\n");
108 }
109 
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
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.
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
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
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
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
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
637 {
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 
652  {
653  FIXME("server %s not supported\n", debugstr_w(pName));
655  return FALSE;
656  }
657 
658  if (!mi2w->pName || (!mi2w->pName[0]) )
659  {
660  FIXME("pName not valid : %s\n", debugstr_w(mi2w->pName));
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));
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 */
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
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 
735  if (lres)
736  {
737  FIXME("server %s not supported\n", debugstr_w(pName));
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));
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) */
804  return FALSE;
805 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired, PHANDLE phkResult, HANDLE hSpooler)
Definition: monitors.c:55
DWORD dwOptions
Definition: solitaire.cpp:23
LPMONITOR2(WINAPI * PInitializePrintMonitor2)(PMONITORINIT, PHANDLE)
Definition: precomp.h:52
const uint16_t * PCWSTR
Definition: typedefs.h:57
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput)
Definition: memory.c:56
BOOL InitializePrintMonitorList(void)
Definition: monitors.c:126
#define ERROR_SUCCESS
Definition: deptool.c:10
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
uint16_t * PWSTR
Definition: typedefs.h:56
HKEYMONITOR hckRegistryRoot
Definition: winsplp.h:748
static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey, PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData, PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime, HANDLE hSpooler)
Definition: monitors.c:79
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
LONG WINAPI RegDeleteKeyW(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey)
Definition: reg.c:1237
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue, PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
Definition: monitors.c:98
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
#define InsertTailList(ListHead, Entry)
#define lstrlenW
Definition: compat.h:609
#define DWORD
Definition: nt_native.h:44
int32_t INT
Definition: typedefs.h:58
LPWSTR pEnvironment
Definition: winspool.h:834
STRSAFEAPI StringCbCatW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:342
struct _MONITOR_INFO_2W MONITOR_INFO_2W
LONG WINAPI RegCreateKeyExW(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ DWORD Reserved, _In_opt_ LPWSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_opt_ LPDWORD lpdwDisposition)
Definition: reg.c:1091
const DWORD cbCurrentEnvironment
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
BOOL WINAPI LocalAddMonitor(PWSTR pName, DWORD Level, PBYTE pMonitors)
Definition: monitors.c:636
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
const WCHAR wszCurrentEnvironment[]
Definition: prtprocenv.h:11
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:365
unsigned char * LPBYTE
Definition: typedefs.h:53
#define FALSE
Definition: types.h:117
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3296
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:111
PMONITORREG pMonitorReg
Definition: winsplp.h:749
#define LoadLibraryW(x)
Definition: compat.h:606
smooth NULL
Definition: ftsmooth.c:416
PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
Definition: tools.c:26
struct _MONITORREG MONITORREG
#define MAXDWORD
#define ERROR_UNKNOWN_PRINT_MONITOR
Definition: winerror.h:1205
PPRINTENV_T validate_envW(LPCWSTR env)
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
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
#define KEY_WRITE
Definition: nt_native.h:1031
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4895
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: monitors.c:396
#define TRACE(s)
Definition: solgame.cpp:4
#define FreeLibrary(x)
Definition: compat.h:607
static LPSTR pName
Definition: security.c:75
static DWORD dwMonitorInfo2Offsets[]
Definition: monitors.c:19
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4116
__wchar_t WCHAR
Definition: xmlstorage.h:180
PBYTE WINAPI PackStrings(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
#define _countof(array)
Definition: sndvol32.h:68
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
#define CopyMemory
Definition: winbase.h:1646
static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
Definition: monitors.c:104
unsigned long DWORD
Definition: ntddk_ex.h:95
#define SetLastError(x)
Definition: compat.h:611
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:3686
LPWSTR pDLLName
Definition: winspool.h:835
static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName, PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
Definition: monitors.c:73
LIST_ENTRY Entry
Definition: precomp.h:73
static const WCHAR L[]
Definition: oid.c:1250
static MONITORREG MonReg
Definition: monitors.c:110
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:454
GLenum GLsizei len
Definition: glext.h:6722
LONG WINAPI RegCreateKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:1199
Definition: typedefs.h:119
static const WCHAR Cleanup[]
Definition: register.c:80
unsigned char BYTE
Definition: xxhash.c:193
BOOL WINAPI LocalDeleteMonitor(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
Definition: monitors.c:724
DWORD cbSize
Definition: winsplp.h:746
LSTATUS WINAPI RegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
Definition: reg.c:1746
#define ERR(fmt,...)
Definition: debug.h:110
static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
Definition: monitors.c:92
#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED
Definition: winerror.h:1211
#define ERROR_PROC_NOT_FOUND
Definition: winerror.h:199
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3827
static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType, const BYTE *pData, DWORD cbData, HANDLE hSpooler)
Definition: monitors.c:86
static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
Definition: monitors.c:67
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
ACCESS_MASK REGSAM
Definition: winreg.h:69
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
DWORD * PDWORD
Definition: pedump.c:68
static LPCWSTR LPCWSTR LPCWSTR env
Definition: db.cpp:168
LIST_ENTRY PrintMonitorList
Definition: monitors.c:11
static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
Definition: monitors.c:61
BOOL WINAPI DllFreeSplStr(PWSTR pwszString)
Definition: memory.c:130
LPMONITOREX(WINAPI * PInitializePrintMonitor)(PWSTR)
Definition: precomp.h:51
GLuint res
Definition: glext.h:9613
BOOL bLocal
Definition: winsplp.h:750
LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
Definition: tools.c:89
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:102
struct _MONITOR2 * PMONITOR2
#define ERROR_INVALID_NAME
Definition: compat.h:103
static LPMONITOR2 pm2
Definition: localmon.c:46
#define GetProcAddress(x, y)
Definition: compat.h:612
struct _MONITOR_INFO_2W * LPMONITOR_INFO_2W
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:2527
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
PLOCAL_PRINT_MONITOR FindPrintMonitor(PCWSTR pwszName)
Definition: monitors.c:28
BOOL AddPrintMonitorList(LPCWSTR pName, LPWSTR DllName)
Definition: monitors.c:457
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
WCHAR * LPWSTR
Definition: xmlstorage.h:184
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1827
struct _MONITOR_INFO_1W MONITOR_INFO_1W
struct _MONITOREX * LPMONITOREX
STRSAFEAPI StringCbCopyW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:166
#define memset(x, y, z)
Definition: compat.h:39
BYTE * PBYTE
Definition: pedump.c:66
static void _LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_1W *ppMonitorInfo, PBYTE *ppMonitorInfoEnd, PDWORD pcbNeeded)
Definition: monitors.c:342
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)
_In_ DWORD _Out_writes_bytes_to_opt_ pcbData void _Inout_ DWORD * pcbData
Definition: wincrypt.h:4949
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions, REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes, PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
Definition: monitors.c:49
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define REG_SZ
Definition: layer.c:22