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 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 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 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 61 static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler) 62 { 63 FIXME("stub\n"); 64 return ERROR_CALL_NOT_IMPLEMENTED; 65 } 66 67 static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler) 68 { 69 FIXME("stub\n"); 70 return ERROR_CALL_NOT_IMPLEMENTED; 71 } 72 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 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 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 92 static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler) 93 { 94 FIXME("stub\n"); 95 return ERROR_CALL_NOT_IMPLEMENTED; 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"); 101 return ERROR_CALL_NOT_IMPLEMENTED; 102 } 103 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 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 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 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 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 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 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