reactos/win32ss/printing/providers/localspl/monitors.c
James Tabor 62c4b828b4 [Printing] Update and Add Functions
More forwards to LocalSpl and LocalMon. At sometime will be merged together.
Bug fixes.
Printer Driver code is a wine hack. (WIP)
Added information for shell tray icon notifications.
Sync wine WinSpool driver tests. Unplugged from build.
2020-08-26 17:12:20 -05:00

806 lines
25 KiB
C

/*
* PROJECT: ReactOS Local Spooler
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Functions related to Print Monitors
* COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
*/
#include "precomp.h"
// Global Variables
LIST_ENTRY PrintMonitorList;
// Local Constants
static DWORD dwMonitorInfo1Offsets[] = {
FIELD_OFFSET(MONITOR_INFO_1W, pName),
MAXDWORD
};
static DWORD dwMonitorInfo2Offsets[] = {
FIELD_OFFSET(MONITOR_INFO_2W, pName),
FIELD_OFFSET(MONITOR_INFO_2W, pEnvironment),
FIELD_OFFSET(MONITOR_INFO_2W, pDLLName),
MAXDWORD
};
PLOCAL_PRINT_MONITOR
FindPrintMonitor(PCWSTR pwszName)
{
PLIST_ENTRY pEntry;
PLOCAL_PRINT_MONITOR pPrintMonitor;
TRACE("FindPrintMonitor(%S)\n", pwszName);
if (!pwszName)
return NULL;
for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
{
pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
if (_wcsicmp(pPrintMonitor->pwszName, pwszName) == 0)
return pPrintMonitor;
}
return NULL;
}
static LONG WINAPI CreateKey(HANDLE hcKey, LPCWSTR pszSubKey, DWORD dwOptions, REGSAM samDesired, PSECURITY_ATTRIBUTES pSecurityAttributes, PHANDLE phckResult, PDWORD pdwDisposition, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI OpenKey(HANDLE hcKey, LPCWSTR pszSubKey, REGSAM samDesired, PHANDLE phkResult, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI CloseKey(HANDLE hcKey, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI DeleteKey(HANDLE hcKey, LPCWSTR pszSubKey, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI EnumKey(HANDLE hcKey, DWORD dwIndex, LPWSTR pszName, PDWORD pcchName, PFILETIME pftLastWriteTime, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI QueryInfoKey(HANDLE hcKey, PDWORD pcSubKeys, PDWORD pcbKey, PDWORD pcValues, PDWORD pcbValue, PDWORD pcbData, PDWORD pcbSecurityDescriptor, PFILETIME pftLastWriteTime,
HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI SetValue(HANDLE hcKey, LPCWSTR pszValue, DWORD dwType, const BYTE* pData, DWORD cbData, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI DeleteValue(HANDLE hcKey, LPCWSTR pszValue, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI EnumValue(HANDLE hcKey, DWORD dwIndex, LPWSTR pszValue, PDWORD pcbValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static LONG WINAPI QueryValue(HANDLE hcKey, LPCWSTR pszValue, PDWORD pType, PBYTE pData, PDWORD pcbData, HANDLE hSpooler)
{
FIXME("stub\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
static MONITORREG MonReg =
{
sizeof(MONITORREG),
CreateKey,
OpenKey,
CloseKey,
DeleteKey,
EnumKey,
QueryInfoKey,
SetValue,
DeleteValue,
EnumValue,
QueryValue
};
BOOL
InitializePrintMonitorList(void)
{
const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors";
const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
DWORD cchMaxSubKey;
DWORD cchPrintMonitorName;
DWORD dwErrorCode;
DWORD dwSubKeys;
DWORD i;
HINSTANCE hinstPrintMonitor = NULL;
HKEY hKey = NULL;
HKEY hSubKey = NULL;
MONITORINIT MonitorInit;
PInitializePrintMonitor pfnInitializePrintMonitor;
PInitializePrintMonitor2 pfnInitializePrintMonitor2;
PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
PWSTR pwszRegistryPath = NULL;
TRACE("InitializePrintMonitorList()\n");
// Initialize an empty list for our Print Monitors.
InitializeListHead(&PrintMonitorList);
// Open the key containing Print Monitors.
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszMonitorsPath, 0, KEY_READ, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
// Get the number of Print Providers and maximum sub key length.
dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, &cchMaxSubKey, NULL, NULL, NULL, NULL, NULL, NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
// Loop through all available Print Providers.
for (i = 0; i < dwSubKeys; i++)
{
// Cleanup tasks from the previous run
if (hSubKey)
{
RegCloseKey(hSubKey);
hSubKey = NULL;
}
if (pwszRegistryPath)
{
DllFreeSplMem(pwszRegistryPath);
pwszRegistryPath = NULL;
}
if (pPrintMonitor)
{
if (pPrintMonitor->pwszFileName)
DllFreeSplMem(pPrintMonitor->pwszFileName);
if (pPrintMonitor->pwszName)
DllFreeSplMem(pPrintMonitor->pwszName);
DllFreeSplMem(pPrintMonitor);
pPrintMonitor = NULL;
}
// Create a new LOCAL_PRINT_MONITOR structure for it.
pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
if (!pPrintMonitor)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
memset( pPrintMonitor, 0, sizeof(LOCAL_PRINT_MONITOR));
// Allocate memory for the Print Monitor Name.
pPrintMonitor->pwszName = DllAllocSplMem((cchMaxSubKey + 1) * sizeof(WCHAR));
if (!pPrintMonitor->pwszName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
// Get the name of this Print Monitor.
cchPrintMonitorName = cchMaxSubKey + 1;
dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, pPrintMonitor->pwszName, &cchPrintMonitorName, NULL, NULL, NULL, NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode);
continue;
}
// Open this Print Monitor's registry key.
dwErrorCode = (DWORD)RegOpenKeyExW(hKey, pPrintMonitor->pwszName, 0, KEY_READ, &hSubKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for Print Provider \"%S\" with status %lu!\n", pPrintMonitor->pwszName, dwErrorCode);
continue;
}
// Get the file name of the Print Monitor.
pPrintMonitor->pwszFileName = AllocAndRegQueryWSZ(hSubKey, L"Driver");
if (!pPrintMonitor->pwszFileName)
continue;
// Try to load it.
hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
if (!hinstPrintMonitor)
{
ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
continue;
}
pPrintMonitor->hModule = hinstPrintMonitor;
// Try to find a Level 2 initialization routine first.
pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
if (pfnInitializePrintMonitor2)
{
// Prepare a MONITORINIT structure.
MonitorInit.cbSize = sizeof(MONITORINIT);
MonitorInit.bLocal = TRUE;
// TODO: Fill the other fields.
MonitorInit.hckRegistryRoot = hKey;
MonitorInit.pMonitorReg = &MonReg;
// Call the Level 2 initialization routine.
pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
if (!pPrintMonitor->pMonitor)
{
ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
continue;
}
FIXME("InitializePrintMonitor2 loaded.\n");
pPrintMonitor->bIsLevel2 = TRUE;
}
else
{
// Try to find a Level 1 initialization routine then.
pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
if (pfnInitializePrintMonitor)
{
// Construct the registry path.
pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
if (!pwszRegistryPath)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
pwszRegistryPath[cchMonitorsPath] = L'\\';
CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
// Call the Level 1 initialization routine.
pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
if (!pPrintMonitor->pMonitor)
{
ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
continue;
}
}
else
{
ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
continue;
}
}
// Add this Print Monitor to the list.
InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
FIXME("InitializePrintMonitorList Handle %p\n",pPrintMonitor->hMonitor);
pPrintMonitor->refcount++;
// Don't let the cleanup routine free this.
pPrintMonitor = NULL;
}
dwErrorCode = ERROR_SUCCESS;
Cleanup:
// Inside the loop
if (hSubKey)
RegCloseKey(hSubKey);
if (pwszRegistryPath)
DllFreeSplMem(pwszRegistryPath);
if (pPrintMonitor)
{
if (pPrintMonitor->pwszFileName)
DllFreeSplMem(pPrintMonitor->pwszFileName);
if (pPrintMonitor->pwszName)
DllFreeSplMem(pPrintMonitor->pwszName);
DllFreeSplMem(pPrintMonitor);
}
// Outside the loop
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
static void
_LocalGetMonitorLevel1(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_1W* ppMonitorInfo, PBYTE* ppMonitorInfoEnd, PDWORD pcbNeeded)
{
DWORD cbMonitorName;
PCWSTR pwszStrings[1];
// Calculate the string lengths.
if (!ppMonitorInfo)
{
cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
*pcbNeeded += sizeof(MONITOR_INFO_1W) + cbMonitorName;
return;
}
// Set the pName field.
pwszStrings[0] = pPrintMonitor->pwszName;
// Copy the structure and advance to the next one in the output buffer.
*ppMonitorInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppMonitorInfo), dwMonitorInfo1Offsets, *ppMonitorInfoEnd);
(*ppMonitorInfo)++;
}
static void
_LocalGetMonitorLevel2(PLOCAL_PRINT_MONITOR pPrintMonitor, PMONITOR_INFO_2W* ppMonitorInfo, PBYTE* ppMonitorInfoEnd, PDWORD pcbNeeded)
{
DWORD cbFileName;
DWORD cbMonitorName;
PCWSTR pwszStrings[3];
// Calculate the string lengths.
if (!ppMonitorInfo)
{
cbMonitorName = (wcslen(pPrintMonitor->pwszName) + 1) * sizeof(WCHAR);
cbFileName = (wcslen(pPrintMonitor->pwszFileName) + 1) * sizeof(WCHAR);
*pcbNeeded += sizeof(MONITOR_INFO_2W) + cbMonitorName + cbCurrentEnvironment + cbFileName;
return;
}
// Set the pName field.
pwszStrings[0] = pPrintMonitor->pwszName;
// Set the pEnvironment field.
pwszStrings[1] = (PWSTR)wszCurrentEnvironment;
// Set the pDLLName field.
pwszStrings[2] = pPrintMonitor->pwszFileName;
// Copy the structure and advance to the next one in the output buffer.
*ppMonitorInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppMonitorInfo), dwMonitorInfo2Offsets, *ppMonitorInfoEnd);
(*ppMonitorInfo)++;
}
BOOL WINAPI
LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
{
DWORD dwErrorCode;
PBYTE pMonitorInfoEnd;
PLIST_ENTRY pEntry;
PLOCAL_PRINT_MONITOR pPrintMonitor;
TRACE("LocalEnumMonitors(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
// Sanity checks.
if (Level > 2)
{
dwErrorCode = ERROR_INVALID_LEVEL;
goto Cleanup;
}
// Begin counting.
*pcbNeeded = 0;
*pcReturned = 0;
// Count the required buffer size and the number of monitors.
for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
{
pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
if (Level == 1)
_LocalGetMonitorLevel1(pPrintMonitor, NULL, NULL, pcbNeeded);
else if (Level == 2)
_LocalGetMonitorLevel2(pPrintMonitor, NULL, NULL, pcbNeeded);
}
// Check if the supplied buffer is large enough.
if (cbBuf < *pcbNeeded)
{
dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
goto Cleanup;
}
// Copy over the Monitor information.
pMonitorInfoEnd = &pMonitors[*pcbNeeded];
for (pEntry = PrintMonitorList.Flink; pEntry != &PrintMonitorList; pEntry = pEntry->Flink)
{
pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
if (Level == 1)
_LocalGetMonitorLevel1(pPrintMonitor, (PMONITOR_INFO_1W*)&pMonitors, &pMonitorInfoEnd, NULL);
else if (Level == 2)
_LocalGetMonitorLevel2(pPrintMonitor, (PMONITOR_INFO_2W*)&pMonitors, &pMonitorInfoEnd, NULL);
(*pcReturned)++;
}
dwErrorCode = ERROR_SUCCESS;
Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
BOOL
AddPrintMonitorList( LPCWSTR pName, LPWSTR DllName )
{
const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\";
const DWORD cchMonitorsPath = _countof(wszMonitorsPath) - 1;
WCHAR wszRegRoot[MAX_PATH] = {0};
DWORD cchPrintMonitorName;
DWORD dwErrorCode;
HINSTANCE hinstPrintMonitor = NULL;
HKEY hKey = NULL;
MONITORINIT MonitorInit;
PInitializePrintMonitor pfnInitializePrintMonitor;
PInitializePrintMonitor2 pfnInitializePrintMonitor2;
PLOCAL_PRINT_MONITOR pPrintMonitor = NULL;
PWSTR pwszRegistryPath = NULL;
FIXME("AddPrintMonitorList( %S, %S)\n",pName, DllName);
StringCbCopyW(wszRegRoot, sizeof(wszRegRoot), wszMonitorsPath);
StringCbCatW(wszRegRoot, sizeof(wszRegRoot), pName);
// Open the key containing Print Monitors.
dwErrorCode = (DWORD)RegOpenKeyW( HKEY_LOCAL_MACHINE, wszRegRoot, &hKey );
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW %S failed with status %lu!\n", wszRegRoot, dwErrorCode);
goto Cleanup;
}
// Create a new LOCAL_PRINT_MONITOR structure for it.
pPrintMonitor = DllAllocSplMem(sizeof(LOCAL_PRINT_MONITOR));
if (!pPrintMonitor)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
memset( pPrintMonitor, 0, sizeof(LOCAL_PRINT_MONITOR));
// Allocate memory for the Print Monitor Name.
pPrintMonitor->pwszName = AllocSplStr( pName );
if (!pPrintMonitor->pwszName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
cchPrintMonitorName = wcslen(pPrintMonitor->pwszName);
if ( DllName == NULL )
{
DWORD namesize;
dwErrorCode = RegQueryValueExW( hKey, L"Driver", NULL, NULL, NULL, &namesize );
if ( dwErrorCode == ERROR_SUCCESS )
{
DllName = DllAllocSplMem(namesize);
RegQueryValueExW( hKey, L"Driver", NULL, NULL, (LPBYTE)DllName, &namesize );
pPrintMonitor->pwszFileName = DllName;
}
else
{
ERR("DllName not found\n");
goto Cleanup;
}
}
else
{
pPrintMonitor->pwszFileName = AllocSplStr( DllName );
}
// Try to load it.
hinstPrintMonitor = LoadLibraryW(pPrintMonitor->pwszFileName);
if (!hinstPrintMonitor)
{
ERR("LoadLibraryW failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
dwErrorCode = GetLastError();
goto Cleanup;
}
pPrintMonitor->hModule = hinstPrintMonitor;
// Try to find a Level 2 initialization routine first.
pfnInitializePrintMonitor2 = (PInitializePrintMonitor2)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor2");
if (pfnInitializePrintMonitor2)
{
// Prepare a MONITORINIT structure.
MonitorInit.cbSize = sizeof(MONITORINIT);
MonitorInit.bLocal = TRUE;
// TODO: Fill the other fields.
MonitorInit.hckRegistryRoot = hKey;
MonitorInit.pMonitorReg = &MonReg;
// Call the Level 2 initialization routine.
pPrintMonitor->pMonitor = (PMONITOR2)pfnInitializePrintMonitor2(&MonitorInit, &pPrintMonitor->hMonitor);
if (!pPrintMonitor->pMonitor)
{
ERR("InitializePrintMonitor2 failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
goto Cleanup;
}
pPrintMonitor->bIsLevel2 = TRUE;
}
else
{
// Try to find a Level 1 initialization routine then.
pfnInitializePrintMonitor = (PInitializePrintMonitor)GetProcAddress(hinstPrintMonitor, "InitializePrintMonitor");
if (pfnInitializePrintMonitor)
{
// Construct the registry path.
pwszRegistryPath = DllAllocSplMem((cchMonitorsPath + 1 + cchPrintMonitorName + 1) * sizeof(WCHAR));
if (!pwszRegistryPath)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
CopyMemory(pwszRegistryPath, wszMonitorsPath, cchMonitorsPath * sizeof(WCHAR));
pwszRegistryPath[cchMonitorsPath] = L'\\';
CopyMemory(&pwszRegistryPath[cchMonitorsPath + 1], pPrintMonitor->pwszName, (cchPrintMonitorName + 1) * sizeof(WCHAR));
// Call the Level 1 initialization routine.
pPrintMonitor->pMonitor = (LPMONITOREX)pfnInitializePrintMonitor(pwszRegistryPath);
if (!pPrintMonitor->pMonitor)
{
ERR("InitializePrintMonitor failed for \"%S\" with error %lu!\n", pPrintMonitor->pwszFileName, GetLastError());
goto Cleanup;
}
}
else
{
ERR("No initialization routine found for \"%S\"!\n", pPrintMonitor->pwszFileName);
dwErrorCode = ERROR_PROC_NOT_FOUND;
goto Cleanup;
}
}
// Add this Print Monitor to the list.
InsertTailList(&PrintMonitorList, &pPrintMonitor->Entry);
FIXME("AddPrintMonitorList Handle %p\n",pPrintMonitor->hMonitor);
pPrintMonitor->refcount++;
// Don't let the cleanup routine free this.
pPrintMonitor = NULL;
dwErrorCode = ERROR_SUCCESS;
Cleanup:
if (pwszRegistryPath)
DllFreeSplMem(pwszRegistryPath);
if (pPrintMonitor)
{
if (pPrintMonitor->pwszFileName)
DllFreeSplMem(pPrintMonitor->pwszFileName);
if (pPrintMonitor->pwszName)
DllFreeSplMem(pPrintMonitor->pwszName);
DllFreeSplMem(pPrintMonitor);
}
// Outside the loop
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
LocalAddMonitor(PWSTR pName, DWORD Level, PBYTE pMonitors)
{
PPRINTENV_T env;
LPMONITOR_INFO_2W mi2w;
HKEY hroot = NULL;
HKEY hentry = NULL;
DWORD disposition;
BOOL res = FALSE;
const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\";
mi2w = (LPMONITOR_INFO_2W) pMonitors;
FIXME("LocalAddMonitor(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
debugstr_w(mi2w->pName), debugstr_w(mi2w->pEnvironment), debugstr_w(mi2w->pDLLName));
if (copy_servername_from_name(pName, NULL))
{
FIXME("server %s not supported\n", debugstr_w(pName));
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
if (!mi2w->pName || (!mi2w->pName[0]) )
{
FIXME("pName not valid : %s\n", debugstr_w(mi2w->pName));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
env = validate_envW(mi2w->pEnvironment);
if (!env)
return FALSE; /* ERROR_INVALID_ENVIRONMENT */
if (!mi2w->pDLLName || (!mi2w->pDLLName[0]) )
{
FIXME("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (RegCreateKeyW(HKEY_LOCAL_MACHINE, wszMonitorsPath, &hroot) != ERROR_SUCCESS) {
ERR("unable to create key %s\n", debugstr_w(wszMonitorsPath));
return FALSE;
}
if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry, &disposition) == ERROR_SUCCESS)
{
/* Some installers set options for the port before calling AddMonitor.
We query the "Driver" entry to verify that the monitor is installed,
before we return an error.
When a user installs two print monitors at the same time with the
same name, a race condition is possible but silently ignored. */
DWORD namesize = 0;
if ((disposition == REG_OPENED_EXISTING_KEY) &&
(RegQueryValueExW(hentry, L"Driver", NULL, NULL, NULL, &namesize) == ERROR_SUCCESS))
{
FIXME("monitor %s already exists\n", debugstr_w(mi2w->pName));
/* 9x use ERROR_ALREADY_EXISTS */
SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
}
else
{
INT len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
res = (RegSetValueExW(hentry, L"Driver", 0, REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
/* Load and initialize the monitor. SetLastError() is called on failure */
res = AddPrintMonitorList( mi2w->pName, mi2w->pDLLName );
if ( !res )
{
RegDeleteKeyW(hroot, mi2w->pName);
}
else
SetLastError(ERROR_SUCCESS); /* Monitor installer depends on this */
}
RegCloseKey(hentry);
}
RegCloseKey(hroot);
return res;
}
BOOL WINAPI
LocalDeleteMonitor(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
{
HKEY hroot = NULL;
LONG lres;
PLOCAL_PRINT_MONITOR pPrintMonitor;
const WCHAR wszMonitorsPath[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors\\";
FIXME("LocalDeleteMonitor(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
debugstr_w(pMonitorName));
lres = copy_servername_from_name(pName, NULL);
if (lres)
{
FIXME("server %s not supported\n", debugstr_w(pName));
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
/* pEnvironment is ignored in Windows for the local Computer */
if (!pMonitorName || !pMonitorName[0])
{
ERR("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pPrintMonitor = FindPrintMonitor( pMonitorName );
if ( pPrintMonitor )
{
if ( pPrintMonitor->refcount ) pPrintMonitor->refcount--;
if ( pPrintMonitor->refcount == 0 )
{ /* Unload the monitor if it's loaded */
RemoveEntryList(&pPrintMonitor->Entry);
if ( pPrintMonitor->bIsLevel2 )
{
PMONITOR2 pm2 = pPrintMonitor->pMonitor;
if ( pm2 && pm2->pfnShutdown )
{
pm2->pfnShutdown(pPrintMonitor->hMonitor);
}
}
if ( pPrintMonitor->hModule )
FreeLibrary(pPrintMonitor->hModule);
if (pPrintMonitor->pwszFileName)
DllFreeSplStr(pPrintMonitor->pwszFileName);
if (pPrintMonitor->pwszName)
DllFreeSplStr(pPrintMonitor->pwszName);
DllFreeSplMem(pPrintMonitor);
pPrintMonitor = NULL;
}
}
else
{
FIXME("Could not find %s\n", debugstr_w(pMonitorName));
}
if (RegCreateKeyW(HKEY_LOCAL_MACHINE, wszMonitorsPath, &hroot) != ERROR_SUCCESS)
{
ERR("unable to create key %s\n", debugstr_w(wszMonitorsPath));
return FALSE;
}
if (RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS)
{
FIXME("%s deleted\n", debugstr_w(pMonitorName));
RegCloseKey(hroot);
return TRUE;
}
FIXME("%s does not exist\n", debugstr_w(pMonitorName));
RegCloseKey(hroot);
/* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
return FALSE;
}