mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 11:35:58 +00:00
62c4b828b4
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.
806 lines
25 KiB
C
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;
|
|
}
|