You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
423 lines
11 KiB
423 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 1995-97 Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
SrvInst.c
|
|
|
|
Purpose:
|
|
|
|
|
|
Server side install code. This code will be called from a process created by the spooler to do a
|
|
"server" side install of a printer driver.
|
|
|
|
Author:
|
|
|
|
Patrick Vine (pvine) - 22 March 2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#pragma hdrstop
|
|
#include "srvinst.hxx"
|
|
|
|
const TCHAR gcszNTPrint[] = _TEXT("inf\\ntprint.inf");
|
|
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
ServerInstall
|
|
|
|
Routine Description:
|
|
|
|
Server side install code to be called by a process created by spooler.
|
|
|
|
Installs the given printer driver - unless a newer driver with the same name
|
|
is installed - from ntprint.inf in %WINDIR%\inf
|
|
No UIs are popped up and the function will fail if UI would be required. Code
|
|
is called by a process created by spooler. The driver name is passed as a command
|
|
line argument to rundll32 in localspl.
|
|
|
|
Localspl.dll spins a rundll32 process (using CreateProcess) which calls the ServerInstall
|
|
entry point in ntprint.dll. Thus ServerInstall will be running in local system context.
|
|
|
|
Arguments:
|
|
|
|
hwnd - Window handle of stub window.
|
|
hInstance, - Rundll instance handle.
|
|
pszCmdLine - Pointer to command line.
|
|
nCmdShow - Show command value always TRUE.
|
|
|
|
Return Value:
|
|
|
|
Returns the last error code. This can be read by the spooler by getting the return code from the process.
|
|
|
|
--*/
|
|
DWORD
|
|
ServerInstallW(
|
|
IN HWND hwnd,
|
|
IN HINSTANCE hInstance,
|
|
IN LPCTSTR pszCmdLine,
|
|
IN UINT nCmdShow
|
|
)
|
|
{
|
|
CServerInstall Installer;
|
|
|
|
if( Installer.ParseCommand((LPTSTR)pszCmdLine) )
|
|
{
|
|
Installer.InstallDriver();
|
|
}
|
|
|
|
//
|
|
// If an error occurs we call ExitProcess. Then the spooler picks up the
|
|
// error code using GetExitCodeProcess. If no error occurs, then we
|
|
// terminate normally
|
|
//
|
|
if (Installer.GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
ExitProcess(Installer.GetLastError());
|
|
}
|
|
|
|
return Installer.GetLastError();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method definitions for CServerInstall Class.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CServerInstall::
|
|
CServerInstall() : _dwLastError(ERROR_SUCCESS),
|
|
_tsDriverName(),
|
|
_tsNtprintInf()
|
|
{
|
|
}
|
|
|
|
CServerInstall::
|
|
~CServerInstall()
|
|
{
|
|
}
|
|
|
|
BOOL
|
|
CServerInstall::
|
|
InstallDriver()
|
|
{
|
|
|
|
if( SetInfToNTPRINTDir() &&
|
|
DriverNotInstalled() )
|
|
{
|
|
_dwLastError = ::InstallDriverSilently(_tsNtprintInf, _tsDriverName, NULL);
|
|
}
|
|
|
|
return (_dwLastError == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Parameter structure:
|
|
|
|
1st word : Flags = default == 0 for now
|
|
|
|
if flags = 0
|
|
2nd word : Pipe name to open
|
|
|
|
--*/
|
|
BOOL
|
|
CServerInstall::
|
|
ParseCommand( LPTSTR pszCommandStr )
|
|
{
|
|
TCHAR * pTemp;
|
|
DWORD dwCount = 0;
|
|
|
|
//
|
|
// If we don't have a valid command string
|
|
//
|
|
if( !pszCommandStr || !*pszCommandStr )
|
|
{
|
|
_dwLastError = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Grap the driver name
|
|
//
|
|
if( !_tsDriverName.bUpdate( pszCommandStr ))
|
|
{
|
|
_dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Cleanup:
|
|
return (_dwLastError == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
CServerInstall::
|
|
GetLastError()
|
|
{
|
|
SetLastError(_dwLastError);
|
|
return _dwLastError;
|
|
}
|
|
|
|
|
|
//
|
|
// Returns: TRUE if SUCCESS, FALSE otherwise
|
|
//
|
|
// Sets the _stInf string to contain %windir%\inf\ntprint.inf
|
|
//
|
|
BOOL
|
|
CServerInstall::
|
|
SetInfToNTPRINTDir()
|
|
{
|
|
UINT uiSize = 0;
|
|
UINT uiAllocSize = 0;
|
|
PTCHAR pData = NULL;
|
|
TCHAR szNTPrintInf[MAX_PATH];
|
|
DWORD dwPos;
|
|
|
|
_dwLastError = ERROR_INVALID_DATA;
|
|
|
|
//
|
|
// Get %windir%
|
|
// If the return is 0 - the call failed.
|
|
// If the return is greater than MAX_PATH we want to fail as something has managed to change
|
|
// the system dir to longer than MAX_PATH which is invalid. If length is the same we also fail
|
|
// since we might add a '\' and gcszNTPrint is longer than 1 for sure!
|
|
//
|
|
uiSize = GetSystemWindowsDirectory( szNTPrintInf, COUNTOF(szNTPrintInf) );
|
|
if( !uiSize || uiSize >= COUNTOF(szNTPrintInf) )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// If we don't end in a \ then add one.
|
|
//
|
|
dwPos = _tcslen(szNTPrintInf) - 1;
|
|
pData = &szNTPrintInf[ dwPos++ ];
|
|
if( *pData++ != _TEXT('\\') )
|
|
{
|
|
*(pData++) = _TEXT('\\');
|
|
++dwPos;
|
|
}
|
|
|
|
*(pData) = 0;
|
|
uiSize = _tcslen( szNTPrintInf ) + _tcslen( gcszNTPrint ) + 1;
|
|
|
|
//
|
|
// If what we've got sums up to a longer string than the allowable length MAX_PATH - fail
|
|
//
|
|
if( uiSize > COUNTOF(szNTPrintInf) )
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Copy the inf\ntprint.inf string onto the end of the %windir%\ string.
|
|
//
|
|
StringCchCopy( pData, COUNTOF(szNTPrintInf) - dwPos, gcszNTPrint);
|
|
|
|
_dwLastError = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if( _dwLastError != ERROR_SUCCESS && szNTPrintInf )
|
|
{
|
|
//
|
|
// Got here due to some error. Get what the called function set the last error to.
|
|
// If the function set a success, set some error code.
|
|
//
|
|
if( (_dwLastError = ::GetLastError()) == ERROR_SUCCESS )
|
|
_dwLastError = ERROR_INVALID_DATA;
|
|
|
|
szNTPrintInf[0] = 0;
|
|
}
|
|
|
|
if( !_tsNtprintInf.bUpdate( szNTPrintInf ) )
|
|
_dwLastError = ::GetLastError();
|
|
|
|
return (_dwLastError == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*+
|
|
|
|
This function enumerates the drivers and finds if there is one of the same name currently installed.
|
|
If there is then open the inf to install with and verify that the inf's version date is newer than the
|
|
already installed driver.
|
|
|
|
Returns: TRUE - if anything fails or the installed date isn't newer than the inf date.
|
|
FALSE - only if the driver is installed AND it's date is newer than the inf's date.
|
|
|
|
-*/
|
|
BOOL
|
|
CServerInstall::
|
|
DriverNotInstalled()
|
|
{
|
|
LPCTSTR pszKey = _TEXT("DriverVer");
|
|
LPTSTR pszEntry = NULL;
|
|
LPDRIVER_INFO_6 pDriverInfo6 = NULL;
|
|
LPBYTE pBuf = NULL;
|
|
PSP_INF_INFORMATION pInfo = NULL;
|
|
SYSTEMTIME Time = {0};
|
|
BOOL bRet = TRUE;
|
|
DWORD dwLength,
|
|
dwRet,
|
|
dwIndex;
|
|
TCHAR *pTemp,
|
|
*pTemp2;
|
|
|
|
if(!EnumPrinterDrivers( NULL, PlatformEnv[MyPlatform].pszName, 6, pBuf, 0, &dwLength, &dwRet ))
|
|
{
|
|
if( ::GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
|
return TRUE;
|
|
|
|
if( (pBuf = (LPBYTE) AllocMem( dwLength )) == NULL ||
|
|
!EnumPrinterDrivers( NULL, PlatformEnv[MyPlatform].pszName, 6, pBuf, dwLength, &dwLength, &dwRet ))
|
|
{
|
|
_dwLastError = ::GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Only way this could succeed is if no drivers installed.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
for( dwIndex = 0, pDriverInfo6 = (LPDRIVER_INFO_6)pBuf; dwIndex < dwRet; dwIndex++, pDriverInfo6++ )
|
|
{
|
|
if( _tcscmp( pDriverInfo6->pName, (LPCTSTR)_tsDriverName ) == 0 )
|
|
break;
|
|
}
|
|
|
|
if(dwIndex >= dwRet)
|
|
{
|
|
//
|
|
// Driver not found
|
|
//
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// The driver has been found... Open up inf and look at it's date.
|
|
//
|
|
|
|
//
|
|
// Firstly get the size that will be needed for pInfo.
|
|
//
|
|
if( !SetupGetInfInformation( (LPCTSTR)_tsNtprintInf, INFINFO_INF_NAME_IS_ABSOLUTE, pInfo, 0, &dwLength ) )
|
|
{
|
|
_dwLastError = ::GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Alloc pInfo and fill it.
|
|
//
|
|
if( (pInfo = (PSP_INF_INFORMATION) AllocMem( dwLength )) != NULL &&
|
|
SetupGetInfInformation( (LPCTSTR)_tsNtprintInf, INFINFO_INF_NAME_IS_ABSOLUTE, pInfo, dwLength, &dwLength ) )
|
|
{
|
|
//
|
|
// Get the size of the date string
|
|
//
|
|
if( SetupQueryInfVersionInformation( pInfo, 0, pszKey, pszEntry, 0, &dwLength ))
|
|
{
|
|
//
|
|
// Alloc pszEntry and fill it.
|
|
//
|
|
if( (pszEntry = (LPTSTR) AllocMem( dwLength*sizeof(TCHAR) )) != NULL &&
|
|
SetupQueryInfVersionInformation( pInfo, 0, pszKey, pszEntry, dwLength, &dwLength ))
|
|
{
|
|
//
|
|
// Now convert the date string into a SYSTEMTIME
|
|
// Date is of the form 03/22/2000
|
|
//
|
|
// Get the month - 03 part
|
|
//
|
|
if( (pTemp = _tcschr( pszEntry, _TEXT('/'))) != NULL )
|
|
{
|
|
*pTemp++ = 0;
|
|
Time.wMonth = (WORD)_ttoi( pszEntry );
|
|
pTemp2 = pTemp;
|
|
|
|
//
|
|
// Get the day - 22 part
|
|
//
|
|
if( (pTemp = _tcschr( pTemp2, _TEXT('/'))) != NULL )
|
|
{
|
|
*pTemp++ = 0;
|
|
Time.wDay = (WORD)_ttoi( pTemp2 );
|
|
pTemp2 = pTemp;
|
|
|
|
//
|
|
// Get the year - 2000 part
|
|
//
|
|
pTemp = _tcschr( pTemp2, _TEXT('/'));
|
|
if( pTemp )
|
|
*pTemp = 0;
|
|
Time.wYear = (WORD)_ttoi( pTemp2 );
|
|
}
|
|
else
|
|
_dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
_dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
_dwLastError = ::GetLastError();
|
|
}
|
|
else
|
|
_dwLastError = ::GetLastError();
|
|
|
|
|
|
//
|
|
// If we got all the way to filling in the year, we may have something useful...
|
|
//
|
|
if( Time.wYear )
|
|
{
|
|
FILETIME ftTime = {0};
|
|
if(SystemTimeToFileTime( &Time, &ftTime ))
|
|
{
|
|
//
|
|
// If the inf time is more recent than what is installed,
|
|
// reinstall, otherwise don't
|
|
//
|
|
if( CompareFileTime(&ftTime, &pDriverInfo6->ftDriverDate) < 1 )
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
//
|
|
// Getting here and return TRUE or FALSE is still a successful call.
|
|
//
|
|
_dwLastError = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
_dwLastError = ERROR_INVALID_PARAMETER;
|
|
|
|
Cleanup:
|
|
if( pBuf )
|
|
FreeMem( pBuf );
|
|
|
|
if( pInfo )
|
|
FreeMem( pInfo );
|
|
|
|
if( pszEntry )
|
|
FreeMem( pszEntry );
|
|
|
|
return bRet;
|
|
}
|
|
|