windows-nt/Source/XPSP1/NT/printscan/print/spooler/splsetup/monitor.c

746 lines
17 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995-97 Microsoft Corporation
All rights reserved.
Module Name:
Monitor.c
Abstract:
Routines for installing monitors
Author:
Muhunthan Sivapragasam (MuhuntS) 30-Nov-1995
Revision History:
--*/
#include "precomp.h"
//
// Keys to search INF files
//
TCHAR cszOptions[] = TEXT("Options");
TCHAR cszPortMonitorSection[] = TEXT("PortMonitors");
TCHAR cszPortMonitorDllKey [] = TEXT("PortMonitorDll");
TCHAR cszMonitorInf[] = TEXT("*.inf");
typedef struct _MON_INFO {
LPTSTR pszName;
LPTSTR pszDllName;
BOOL bInstalled;
} MON_INFO, *PMON_INFO;
typedef struct _MONITOR_SETUP_INFO {
PMON_INFO *ppMonInfo;
DWORD dwCount;
LPTSTR pszInfFile; // Valid only for OEM disk INF
LPTSTR pszServerName;
} MONITOR_SETUP_INFO, *PMONITOR_SETUP_INFO;
VOID
FreeMonInfo(
PMON_INFO pMonInfo
)
/*++
Routine Description:
Free memory for a MON_INFO structure and the strings in it
Arguments:
pMonInfo : MON_INFO structure pointer
Return Value:
Nothing
--*/
{
if ( pMonInfo ) {
LocalFreeMem(pMonInfo->pszName);
LocalFreeMem(pMonInfo->pszDllName);
LocalFreeMem(pMonInfo);
}
}
PMON_INFO
AllocMonInfo(
IN LPTSTR pszName,
IN LPTSTR pszDllName, OPTIONAL
IN BOOL bInstalled,
IN BOOL bAllocStrings
)
/*++
Routine Description:
Allocate memory for a MON_INFO structure and create strings
Arguments:
pszName : Monitor name
pszDllName : Monitor DLL name
bAllocStrings : TRUE if routine should allocated memory and create string
copies, else just assign the pointers
Return Value:
Pointer to the created MON_INFO structure. NULL on error.
--*/
{
PMON_INFO pMonInfo;
pMonInfo = (PMON_INFO) LocalAllocMem(sizeof(*pMonInfo));
if ( !pMonInfo )
return NULL;
if ( bAllocStrings ) {
pMonInfo->pszName = AllocStr(pszName);
pMonInfo->pszDllName = AllocStr(pszDllName);
if ( !pMonInfo->pszName ||
(pszDllName && !pMonInfo->pszDllName) ) {
FreeMonInfo(pMonInfo);
return NULL;
}
} else {
pMonInfo->pszName = pszName;
pMonInfo->pszDllName = pszDllName;
}
pMonInfo->bInstalled = bInstalled;
return pMonInfo;
}
VOID
PSetupDestroyMonitorInfo(
IN OUT HANDLE h
)
/*++
Routine Description:
Free memory allocated to a MONITOR_SETUP_INFO structure and its contents
Arguments:
h : A handle got by call to PSetupCreateMonitorInfo
Return Value:
Nothing
--*/
{
PMONITOR_SETUP_INFO pMonitorSetupInfo = (PMONITOR_SETUP_INFO) h;
DWORD Index;
if ( pMonitorSetupInfo ) {
if ( pMonitorSetupInfo->ppMonInfo ) {
for ( Index = 0 ; Index < pMonitorSetupInfo->dwCount ; ++Index )
FreeMonInfo(pMonitorSetupInfo->ppMonInfo[Index]);
LocalFreeMem(pMonitorSetupInfo->ppMonInfo);
}
LocalFreeMem(pMonitorSetupInfo->pszInfFile);
LocalFreeMem(pMonitorSetupInfo->pszServerName);
LocalFreeMem(pMonitorSetupInfo);
}
}
BOOL
IsMonitorFound(
IN LPVOID pBuf,
IN DWORD dwReturned,
IN LPTSTR pszName
)
/*++
Routine Description:
Find out if the given monitor name is found in the buffer returned from
an EnumMonitors call to spooler
Arguments:
pBuf : Buffer used on a succesful EnumMonitor call to spooler
dwReturned : Count returned by spooler on EnumMonitor
pszMonName : Monitor name we are searching for
Return Value:
TRUE if monitor is found, FALSE else
--*/
{
PMONITOR_INFO_2 pMonitor2;
DWORD Index;
for ( Index = 0, pMonitor2 = (PMONITOR_INFO_2) pBuf ;
Index < dwReturned ;
++Index, (LPBYTE)pMonitor2 += sizeof(MONITOR_INFO_2) ) {
if ( !lstrcmpi(pszName, pMonitor2->pName) )
return TRUE;
}
return FALSE;
}
PMONITOR_SETUP_INFO
CreateMonitorInfo(
LPCTSTR pszServerName
)
/*++
Routine Description:
Finds all installed and installable monitors.
Arguments:
pSelectedDrvInfo : Pointer to the selected driver info (optional)
Return Value:
A pointer to MONITOR_SETUP_INFO on success,
NULL on error
--*/
{
PMONITOR_SETUP_INFO pMonitorSetupInfo = NULL;
PMON_INFO *ppMonInfo;
PMONITOR_INFO_2 pMonitor2;
LONG Index, Count = 0;
BOOL bFail = TRUE;
DWORD dwNeeded, dwReturned;
LPBYTE pBuf = NULL;
LPTSTR pszMonName;
//
// First query spooler for installed monitors. If we fail let's quit
//
if ( !EnumMonitors((LPTSTR)pszServerName, 2, NULL,
0, &dwNeeded, &dwReturned) ) {
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
!(pBuf = LocalAllocMem(dwNeeded)) ||
!EnumMonitors((LPTSTR)pszServerName,
2,
pBuf,
dwNeeded,
&dwNeeded,
&dwReturned) ) {
goto Cleanup;
}
}
//
// We know how many monitors we have to display now
//
pMonitorSetupInfo = (PMONITOR_SETUP_INFO) LocalAllocMem(sizeof(*pMonitorSetupInfo));
if ( !pMonitorSetupInfo )
goto Cleanup;
ZeroMemory(pMonitorSetupInfo, sizeof(*pMonitorSetupInfo));
//
// pMonitorSetupInfo->dwCount could be adjusted later not to list duplicate
// entries. We are allocating max required buffer here
//
pMonitorSetupInfo->dwCount = dwReturned;
pMonitorSetupInfo->ppMonInfo = (PMON_INFO *)
LocalAllocMem(pMonitorSetupInfo->dwCount*sizeof(PMON_INFO));
ppMonInfo = pMonitorSetupInfo->ppMonInfo;
if ( !ppMonInfo )
goto Cleanup;
for ( Index = 0, pMonitor2 = (PMONITOR_INFO_2) pBuf ;
Index < (LONG) dwReturned ;
++Index, (LPBYTE)pMonitor2 += sizeof(MONITOR_INFO_2) ) {
*ppMonInfo++ = AllocMonInfo(pMonitor2->pName,
pMonitor2->pDLLName,
TRUE,
TRUE);
}
bFail = FALSE;
Cleanup:
if ( pBuf )
LocalFreeMem(pBuf);
if ( bFail ) {
PSetupDestroyMonitorInfo(pMonitorSetupInfo);
pMonitorSetupInfo = NULL;
}
return pMonitorSetupInfo;
}
BOOL
AddPrintMonitor(
IN LPCTSTR pszName,
IN LPCTSTR pszDllName
)
/*++
Routine Description:
Add a print monitor by calling AddMonitor to spooler
Arguments:
pszName : Name of the monitor
pszDllName : Monitor dll name
Return Value:
TRUE if monitor was succesfully added or it is already installed,
FALSE on failure
--*/
{
MONITOR_INFO_2 MonitorInfo2;
MonitorInfo2.pName = (LPTSTR) pszName;
MonitorInfo2.pEnvironment = NULL;
MonitorInfo2.pDLLName = (LPTSTR) pszDllName;
//
// Call is succesful if add returned TRUE, or monitor is already installed
//
if ( AddMonitor(NULL, 2, (LPBYTE) &MonitorInfo2) ||
GetLastError() == ERROR_PRINT_MONITOR_ALREADY_INSTALLED ) {
return TRUE;
} else {
return FALSE;
}
}
PMON_INFO
MonInfoFromName(
IN PMONITOR_SETUP_INFO pMonitorSetupInfo,
IN LPCTSTR pszMonitorName
)
{
PMON_INFO pMonInfo;
DWORD dwIndex;
if ( !pMonitorSetupInfo ) {
return NULL;
}
for ( dwIndex = 0 ; dwIndex < pMonitorSetupInfo->dwCount ; ++dwIndex ) {
pMonInfo = pMonitorSetupInfo->ppMonInfo[dwIndex];
if ( !lstrcmp(pszMonitorName, pMonInfo->pszName) ) {
return pMonInfo;
}
}
return NULL;
}
BOOL
InstallOnePortMonitor(HWND hwnd,
HINF hInf,
LPTSTR pMonitorName,
LPTSTR pSectionName,
LPTSTR pSourcePath)
/*++
Routine Description:
Install one port monitor by copying files and calling spooler to add it
Arguments:
hwnd : Window handle of current top-level window
hInf : handle to the INF file
pMonitorName : port monitor display name
pSectionName : install section within the INF for the port monitor
Return Value:
TRUE if a port monitor was successfully installed
FALSE if not
--*/
{
DWORD NameLen;
BOOL bSuccess = FALSE;
HSPFILEQ InstallQueue = {0};
PVOID pQueueContext = NULL;
LPTSTR pMonitorDllName;
NameLen = MAX_PATH;
if ((pMonitorDllName = LocalAllocMem(NameLen * sizeof(TCHAR))) == NULL)
{
goto Cleanup;
}
//
// Find the port monitor DLL name
//
if (!SetupGetLineText(NULL, hInf, pSectionName, cszPortMonitorDllKey, pMonitorDllName, NameLen, NULL))
{
goto Cleanup;
}
//
// perform the installation
//
if ((InstallQueue = SetupOpenFileQueue()) == INVALID_HANDLE_VALUE)
{
goto Cleanup;
}
if (!SetupInstallFilesFromInfSection(hInf, NULL, InstallQueue, pSectionName, pSourcePath,
SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP))
{
goto Cleanup;
}
//
// Commit the file queue. This gets all files copied over.
//
pQueueContext = SetupInitDefaultQueueCallback(hwnd);
if ( !pQueueContext )
{
goto Cleanup;
}
bSuccess = SetupCommitFileQueue(hwnd,
InstallQueue,
SetupDefaultQueueCallback,
pQueueContext);
if ( !bSuccess )
goto Cleanup;
bSuccess = AddPrintMonitor(pMonitorName, pMonitorDllName);
Cleanup:
if (pQueueContext)
{
SetupTermDefaultQueueCallback(pQueueContext);
}
if (pMonitorDllName)
{
LocalFreeMem(pMonitorDllName);
}
SetupCloseFileQueue(InstallQueue);
if (!bSuccess)
{
LPTSTR pszFormat = NULL, pszPrompt = NULL, pszTitle = NULL;
pszFormat = GetStringFromRcFile(IDS_ERROR_INST_PORT_MONITOR);
pszTitle = GetStringFromRcFile(IDS_INSTALLING_PORT_MONITOR);
if ( pszFormat && pszTitle)
{
pszPrompt = LocalAllocMem((lstrlen(pszFormat) + lstrlen(pMonitorName) + 2)
* sizeof(TCHAR));
if ( pszPrompt )
{
wsprintf(pszPrompt, pszFormat, pMonitorName);
MessageBox(hwnd, pszPrompt, pszTitle, MB_OK);
LocalFreeMem(pszPrompt);
}
}
LocalFreeMem(pszFormat);
LocalFreeMem(pszTitle);
}
return bSuccess;
}
BOOL
InstallAllPortMonitorsFromInf(HWND hwnd,
HINF hInfFile,
LPTSTR pSourcePath)
/*++
Routine Description:
Install all port monitors listed in one INF
Arguments:
hwnd : Window handle of current top-level window
hInfFile : handle of the INF file
pSourcePath : path to the INF file (without the name of the INF)
Return Value:
TRUE if at least one port monitor was successfully installed
FALSE if not
--*/
{
LPTSTR pMonitorName = NULL, pSectionName= NULL;
DWORD NameLen;
BOOL bSuccess = FALSE;
INFCONTEXT Context = {0};
NameLen = MAX_PATH;
if (((pMonitorName = LocalAllocMem(NameLen * sizeof(TCHAR))) == NULL) ||
((pSectionName = LocalAllocMem(NameLen * sizeof(TCHAR))) == NULL))
{
goto Cleanup;
}
//
// Go through the list of port monitors
//
if (!SetupFindFirstLine(hInfFile, cszPortMonitorSection, NULL, &Context))
{
goto Cleanup;
}
do
{
//
// get the key name
//
if (!SetupGetStringField(&Context, 0, pMonitorName, NameLen, NULL))
{
goto Cleanup;
}
//
// get the section name
//
if (!SetupGetStringField(&Context, 1, pSectionName, NameLen, NULL))
{
goto Cleanup;
}
bSuccess = InstallOnePortMonitor(hwnd, hInfFile, pMonitorName, pSectionName, pSourcePath) ||
bSuccess;
} while (SetupFindNextLine(&Context, &Context));
Cleanup:
if (pMonitorName)
{
LocalFreeMem(pMonitorName);
}
if (pSectionName)
{
LocalFreeMem(pSectionName);
}
return bSuccess;
}
BOOL
PSetupInstallMonitor(
IN HWND hwnd
)
/*++
Routine Description:
Install a print monitor by copying files, and calling spooler to add it
Arguments:
hwnd : Window handle of current top-level window
Return Value:
TRUE if at least one port monitor was successfully installed
FALSE if not
--*/
{
PMONITOR_SETUP_INFO pMonitorSetupInfo = NULL;
PMON_INFO *ppMonInfo, pMonInfo;
HINF hInf = INVALID_HANDLE_VALUE;
INFCONTEXT InfContext;
TCHAR szInfPath[MAX_PATH];
LPTSTR pszTitle, pszPrintMonitorPrompt;
WIN32_FIND_DATA FindData ={0};
HANDLE hFind;
size_t PathLen;
BOOL bRet = FALSE;
pszTitle = GetStringFromRcFile(IDS_INSTALLING_PORT_MONITOR);
pszPrintMonitorPrompt = GetStringFromRcFile(IDS_PROMPT_PORT_MONITOR);
if (!pszTitle || ! pszPrintMonitorPrompt)
{
goto Cleanup;
}
//
// Ask the user where the inf file with the port monitor info resides
//
GetCDRomDrive(szInfPath);
if ( !PSetupGetPathToSearch(hwnd,
pszTitle,
pszPrintMonitorPrompt,
cszMonitorInf,
TRUE,
szInfPath) ) {
goto Cleanup;
}
//
// find the INF(s) in the path. There must be one else SetupPromptForPath would've complained
//
PathLen = _tcslen(szInfPath);
if (PathLen > MAX_PATH - _tcslen(cszMonitorInf) - 2) // -2 for terminating zero and backslash
{
DBGMSG(DBG_WARN, ("PSetupInstallMonitor: Path too long\n"));
SetLastError(ERROR_BUFFER_OVERFLOW);
goto Cleanup;
}
ASSERT(PathLen);
if (szInfPath[PathLen-1] != _T('\\'))
{
szInfPath[PathLen++] = _T('\\');
szInfPath[PathLen] = 0;
}
_tcscat(szInfPath, cszMonitorInf);
hFind = FindFirstFile(szInfPath, &FindData);
if (hFind != INVALID_HANDLE_VALUE)
{
HANDLE hInfFile;
do
{
if (PathLen + _tcslen(FindData.cFileName) >= MAX_PATH)
{
DBGMSG(DBG_WARN, ("PSetupInstallMonitor: Path for %s%s too long - file skipped\n", szInfPath, FindData.cFileName));
SetLastError(ERROR_BUFFER_OVERFLOW);
continue;
}
_tcscpy(&(szInfPath[PathLen]), FindData.cFileName);
hInfFile = SetupOpenInfFile(szInfPath, _T("Printer"), INF_STYLE_WIN4, NULL);
if (hInfFile != INVALID_HANDLE_VALUE)
{
//
// if the file has a section on port monitors, install it
//
if ( SetupGetLineCount(hInfFile, cszPortMonitorSection) > 0 )
{
//
// cut off the INF name from the path
//
szInfPath[PathLen -1] = 0;
//
// bRet should be TRUE if there was at least one print monitor successfully installed
//
bRet = InstallAllPortMonitorsFromInf(hwnd, hInfFile, szInfPath) || bRet;
//
// Put the trailing backslash back on
//
szInfPath[PathLen -1] = _T('\\');
}
SetupCloseInfFile(hInfFile);
}
} while ( FindNextFile(hFind, &FindData) );
FindClose(hFind);
}
Cleanup:
if (pszTitle)
{
LocalFreeMem(pszTitle);
}
if (pszPrintMonitorPrompt)
{
LocalFreeMem(pszPrintMonitorPrompt);
}
return bRet;
}
HANDLE
PSetupCreateMonitorInfo(
IN HWND hwnd,
IN LPCTSTR pszServerName
)
{
return (HANDLE) CreateMonitorInfo(pszServerName);
}
BOOL
PSetupEnumMonitor(
IN HANDLE h,
IN DWORD dwIndex,
OUT LPTSTR pMonitorName,
IN OUT LPDWORD pdwSize
)
{
PMONITOR_SETUP_INFO pMonitorSetupInfo = (PMONITOR_SETUP_INFO) h;
PMON_INFO pMonInfo;
DWORD dwNeeded;
if ( dwIndex >= pMonitorSetupInfo->dwCount ) {
SetLastError(ERROR_NO_MORE_ITEMS);
return FALSE;
}
pMonInfo = pMonitorSetupInfo->ppMonInfo[dwIndex];
dwNeeded = lstrlen(pMonInfo->pszName) + 1;
if ( dwNeeded > *pdwSize ) {
*pdwSize = dwNeeded;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
lstrcpy(pMonitorName, pMonInfo->pszName);
return TRUE;
}