/*++ 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; }