|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
pnpdrivers.c
Abstract:
Process Update PnP Drivers section of WINBOM.INI Task performed will be:
Author:
Donald McNamara (donaldm) 5/11/2000
Revision History:
--*/ #include "factoryp.h"
#include <newdev.h> // UpdateDriverForPlugAndPlayDevices constants
#define PNP_CREATE_PIPE_EVENT _T("PNP_Create_Pipe_Event")
#define PNP_NO_INSTALL_EVENTS _T("PnP_No_Pending_Install_Events")
#define PNP_EVENT_TIMEOUT 120000 // 2 minutes
#define PNP_INSTALL_TIMEOUT 450000 // 7 1/2 minutes
#define DIR_DEFAULT_ROOT _T("%SystemRoot%\\drivers")
#define STR_FLOPPY _T("FLOPPY:\\")
#define LEN_STR_FLOPPY ( AS(STR_FLOPPY) - 1 )
#define STR_CDROM _T("CDROM:\\")
#define LEN_STR_CDROM ( AS(STR_CDROM) - 1 )
static HANDLE WaitForOpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName, DWORD dwMilliseconds);
BOOL StartPnP() { HANDLE hEvent; BOOL bRet = FALSE;
// If we have already start PnP once, should not try to signal it again.
//
if ( GET_FLAG(g_dwFactoryFlags, FLAG_PNP_STARTED) ) return TRUE;
//
// Signal the PNP_CREATE_PIPE_EVENT, with the UMPNPMGR is waiting on, so that
// it can start processing installed devices.
//
// First we must wait till we can open the event, because if it doesn't already exist
// then the PnP wont be listening to it when we signal it.
//
if ( hEvent = WaitForOpenEvent(EVENT_MODIFY_STATE, FALSE, PNP_CREATE_PIPE_EVENT, PNP_EVENT_TIMEOUT) ) { // Signal the event now so that pnp starts up.
//
if ( !SetEvent(hEvent) ) { // Unable to signal the event to tell pnp to start for some reason.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_PNPSIGNALEVENT, GetLastError()); } else { SET_FLAG(g_dwFactoryFlags, FLAG_PNP_STARTED); bRet = TRUE; }
// We are done with this event.
//
CloseHandle(hEvent); } else { // Couldn't open up the event to tell pnp to get going.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_PNPSTARTEVENT, GetLastError()); }
return bRet; }
BOOL WaitForPnp(DWORD dwTimeOut) { HANDLE hEvent; BOOL bRet = TRUE;
// If we have already waited once, should have to wait again
// (at least I think that is right).
//
if ( GET_FLAG(g_dwFactoryFlags, FLAG_PNP_DONE) ) return TRUE;
//
// Wait for the PnP_No_Pending_Install_Events event, with the UMPNPMGR signals when it is done.
//
// Try to open the pnp finished install event.
//
if ( hEvent = WaitForOpenEvent(SYNCHRONIZE, FALSE, PNP_NO_INSTALL_EVENTS, PNP_EVENT_TIMEOUT) ) { DWORD dwError; // Lets wait for the event to be signaled that pnp is all done.
//
dwError = WaitForSingleObject(hEvent, dwTimeOut); if ( WAIT_OBJECT_0 != dwError ) { // Waiting on the event failed for some reason.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_PNPWAITFINISH, ( WAIT_FAILED == dwError ) ? GetLastError() : dwError); } else { // Woo hoo, looks like everything worked.
//
SET_FLAG(g_dwFactoryFlags, FLAG_PNP_DONE); bRet = TRUE; }
// Make sure we close the event handle.
//
CloseHandle(hEvent); } else { // Couldn't open up the event to wait on.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_PNPFINISHEVENT, GetLastError()); }
return bRet; }
/*++
=============================================================================== Routine Description:
BOOL UpdateDrivers This routine will walk through the list of updated drivers presented in the WINBOM, and then copy all of the driver files for each one
Arguments:
lpStateData->lpszWinBOMPath - Path to the WinBOM file. Return Value:
TRUE if all drivers files where copied FALSE if there was an error
=============================================================================== --*/
BOOL UpdateDrivers(LPSTATEDATA lpStateData) { BOOL bRet = TRUE; LPTSTR lpszWinBOMPath = lpStateData->lpszWinBOMPath, lpszDevicePath, lpszRootPath, lpszDefRoot, lpszDst, lpszSrc, lpszBuffer, lpszKey, lpszDontCare; TCHAR szDstPath[MAX_PATH], szSrcPath[MAX_PATH], szPathBuffer[MAX_PATH], szNetShare[MAX_PATH], cDriveLetter; DWORD dwKeyLen, cbDevicePath, dwDevicePathLen, dwOldSize; NET_API_STATUS nErr;
// Get a buffer for the device paths. It will be either empty if they
// don't have the optional additional paths key in the winbom.
//
if ( NULL == (lpszDevicePath = IniGetStringEx(lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_VAL_WBOM_DEVICEPATH, NULL, &cbDevicePath)) ) { // We must have a buffer for the device path we will update in the registry.
//
cbDevicePath = 256; dwDevicePathLen = 0; if ( NULL == (lpszDevicePath = (LPTSTR) MALLOC(cbDevicePath * sizeof(TCHAR))) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_MEMORY, GetLastError()); return FALSE; } } else { dwDevicePathLen = lstrlen(lpszDevicePath); }
// Now get the optional root path for the drivers to be copied down.
//
lpszRootPath = IniGetString(lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_VAL_WBOM_PNP_DIR, NULL);
// We have to have something for the root path even if the key isn't there.
//
lpszDefRoot = lpszRootPath ? lpszRootPath : DIR_DEFAULT_ROOT;
// Try to get the whole driver section in the winbom.
//
lpszBuffer = IniGetSection(lpszWinBOMPath, INI_SEC_WBOM_DRIVERS); if ( lpszBuffer ) { // Process all lines in this section. The format of the section is:
//
// source=destination
//
// The source can be any valid source path. If this path is a
// UNC path, then we will connect to it. It can also start with
// FLOPPY:\ or CDROM:\, with will be replace with the right drive
// letter.
//
// The destination is the directory relative to target root that
// we will use to copy the updated drivers into. It will be added,
// along with any subdirs, to the device path in the registry.
//
for ( lpszKey = lpszBuffer; *lpszKey; lpszKey += dwKeyLen ) { // Save the length of this string so we know where
// the next key starts.
//
dwKeyLen = lstrlen(lpszKey) + 1;
// Look for the value of the key after the = sign.
//
if ( lpszDst = StrChr(lpszKey, _T('=')) ) { // Terminate the source where the = is, and then
// make sure there is something after it for the
// destination.
//
*lpszDst++ = NULLCHR; if ( NULLCHR == *lpszDst ) { lpszDst = NULL; } }
// We have to have a value to copy the driver.
//
if ( lpszDst ) { //
// At this level in the code (until a little bit later), set the destination
// pointer to NULL to indicate an error. That will make it so we don't add
// the path to the device path in the registry. It will also return a failure
// for this state, but we will keep on going with the next key.
//
// Set the source root as the key name.
//
lpszSrc = lpszKey;
// Create the expanded full path for the destination.
//
lstrcpyn(szDstPath, lpszDefRoot, AS(szDstPath)); AddPathN(szDstPath, lpszDst, AS(szDstPath)); ExpandFullPath(NULL, szDstPath, AS(szDstPath));
// Make sure we have a destination to copy to before we continue.
//
if ( NULLCHR == szDstPath[0] ) { // Log an error and set the destination pointer to NULL.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_DSTBAD, lpszDst, GetLastError()); lpszDst = NULL; } else { //
// At this level in the code (disregard the above comment), set the
// source pointer to NULL to indicate an error. That will make it so
// we don't add the destination path to the device path in the registry
// or try and copy any files to it. It will also return a failure for
// this state, but we will keep on going with the next key.
//
// Determine if this is a UNC path. If it is not, then it is
// assumed to be a local path.
//
szNetShare[0] = NULLCHR; if ( GetUncShare(lpszSrc, szNetShare, AS(szNetShare)) && szNetShare[0] ) { // Connect to the UNC , using the supplied credentials.
//
if ( NERR_Success != (nErr = FactoryNetworkConnect(szNetShare, lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, TRUE)) ) { // Log an error and set the source pointer to NULL.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_NETCONNECT, szNetShare, nErr); szNetShare[0] = NULLCHR; lpszSrc = NULL; } } else if ( ( lstrlen(lpszSrc) >= LEN_STR_FLOPPY ) && ( CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpszSrc, LEN_STR_FLOPPY, STR_FLOPPY, LEN_STR_FLOPPY) == CSTR_EQUAL ) ) { // Make sure there is a floppy drive in the system.
//
if ( NULLCHR == (cDriveLetter = GetDriveLetter(DRIVE_REMOVABLE)) ) { // Log an error and set the source pointer to NULL.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_FLOPPYNOTFOUND, lpszSrc); lpszSrc = NULL; } else { // Advance the source pointer to the character before the :\ and then
// set that character to the driver letter returned for the floppy.
//
lpszSrc += LEN_STR_FLOPPY - 3; *lpszSrc = cDriveLetter; } } else if ( ( lstrlen(lpszSrc) >= LEN_STR_CDROM ) && ( CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, lpszSrc, LEN_STR_CDROM, STR_CDROM, LEN_STR_CDROM) == CSTR_EQUAL ) ) { // Make sure there is a CD-ROM drive in the system.
//
if ( NULLCHR == (cDriveLetter = GetDriveLetter(DRIVE_CDROM)) ) { // Log an error and set the source pointer to NULL.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_CDROMNOTFOUND, lpszSrc); lpszSrc = NULL; } else { // Advance the source pointer to the character before the :\ and then
// set that character to the driver letter returned for the CD-ROM.
//
lpszSrc += LEN_STR_CDROM - 3; *lpszSrc = cDriveLetter; } }
// If there is a source, expand it out.
//
if ( lpszSrc ) { // Create the expanded full path for the source.
//
ExpandFullPath(lpszSrc, szSrcPath, AS(szSrcPath));
// Make sure we have a source to copy to before we continue.
//
if ( NULLCHR == szSrcPath[0] ) { // Log an error and set the source pointer to NULL.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_SRCBAD, lpszSrc, GetLastError()); lpszSrc = NULL; } else if ( !DirectoryExists(szSrcPath) || !CopyDirectory(szSrcPath, szDstPath) ) { // Log an error and set the source pointer to NULL.
//
FacLogFile(0 | LOG_ERR, IDS_ERR_DRVCOPYFAILED, szSrcPath, szDstPath); lpszSrc = NULL; } }
// Source will only be valid if we actually copied some drivers.
//
if ( NULL == lpszSrc ) { // Set this so we don't add this path to the registry.
//
lpszDst = NULL; }
// Clean up and drive mappings we may have done to a remote Server/Share.
//
if ( ( szNetShare[0] ) && ( NERR_Success != (nErr = FactoryNetworkConnect(szNetShare, lpszWinBOMPath, NULL, FALSE)) ) ) { // Log a warning.
//
FacLogFile(2, IDS_WRN_NETDISCONNECT, szNetShare, nErr); } }
// Now if the destination pointer is NULL, we know we need to
// return an error for this state.
//
if ( NULL == lpszDst ) { bRet = FALSE; } } else { // If there was no =, then just use the key part
// as the dest and add it to the device path.
//
lpszDst = lpszKey; }
// Now if we have something to add to our device path,
// add it now.
//
if ( lpszDst ) { // Make sure our buffer is still big enough.
// The two extra are for the possible semi-colon
// we might add and one more to be safe. We
// don't have to worry about the null terminator
// because we do less than or equal to our current
// buffer size.
//
dwOldSize = cbDevicePath; dwDevicePathLen += lstrlen(lpszDst); while ( cbDevicePath <= (dwDevicePathLen + 2) ) { cbDevicePath *= 2; }
// Make sure we still have a buffer.
//
if ( cbDevicePath > dwOldSize ) { LPTSTR lpszTmpDevicePath = (LPTSTR) REALLOC(lpszDevicePath, cbDevicePath * sizeof(TCHAR));
if ( NULL == lpszTmpDevicePath ) { // If this realloc fails, we just need to bail.
//
FREE(lpszDevicePath); FREE(lpszRootPath); FREE(lpszBuffer); FacLogFile(0 | LOG_ERR, IDS_ERR_MEMORY, GetLastError()); return FALSE; } else { lpszDevicePath = lpszTmpDevicePath; } }
// If we already have added a path, tack on a semicolon.
//
if ( *lpszDevicePath ) { if ( FAILED ( StringCchCat ( lpszDevicePath, cbDevicePath, _T(";") ) ) ) { FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpszDevicePath, _T(";") ); } dwDevicePathLen++; }
// Now add our path.
//
if ( FAILED ( StringCchCat ( lpszDevicePath, cbDevicePath, lpszDst) ) ) { FacLogFileStr(3, _T("StringCchCat failed %s %s\n"), lpszDevicePath, lpszDst ) ; }
} }
FREE(lpszBuffer); }
// If we are saving this list to the registry, then
// we need to add to our buffer.
//
if ( *lpszDevicePath && !UpdateDevicePath(lpszDevicePath, lpszDefRoot, TRUE) ) { FacLogFile(0 | LOG_ERR, IDS_ERR_UPDATEDEVICEPATH, lpszDevicePath); bRet = FALSE; }
// Clean up any memory (macro checks for NULL).
//
FREE(lpszRootPath); FREE(lpszDevicePath);
return bRet; }
BOOL DisplayUpdateDrivers(LPSTATEDATA lpStateData) { return ( IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERS, NULL, NULL) || IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_VAL_WBOM_DEVICEPATH, NULL) ); }
BOOL InstallDrivers(LPSTATEDATA lpStateData) { // Should always let normal pnp finish before we start
// enumerating all the devices checking for updated drivers.
//
WaitForPnp(PNP_INSTALL_TIMEOUT);
// Make sure we want to do this.
//
if ( !DisplayInstallDrivers(lpStateData) ) { return TRUE; }
return UpdatePnpDeviceDrivers(); }
BOOL DisplayInstallDrivers(LPSTATEDATA lpStateData) { return ( ( IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_KEY_WBOM_INSTALLDRIVERS, INI_VAL_WBOM_YES) ) || ( !GET_FLAG(g_dwFactoryFlags, FLAG_OOBE) && IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERS, NULL, NULL) ) ); }
BOOL NormalPnP(LPSTATEDATA lpStateData) { return StartPnP(); }
BOOL WaitPnP(LPSTATEDATA lpStateData) { // If this is the extra wait state, we only
// do it if there is a certain key in the winbom.
//
if ( DisplayWaitPnP(lpStateData) ) { return WaitForPnp(PNP_INSTALL_TIMEOUT); }
return TRUE; }
BOOL DisplayWaitPnP(LPSTATEDATA lpStateData) { BOOL bRet = IniSettingExists(lpStateData->lpszWinBOMPath, INI_SEC_WBOM_DRIVERUPDATE, INI_KEY_WBOM_PNPWAIT, INI_VAL_WBOM_YES);
if ( stateWaitPnP == lpStateData->state ) { bRet = !bRet; }
return bRet; }
BOOL SetDisplay(LPSTATEDATA lpStateData) { // If this is the second set display, only bother if we
// re-enumerated the installed drivers.
//
if ( ( stateSetDisplay2 == lpStateData->state ) && ( !DisplayInstallDrivers(lpStateData) ) ) { return TRUE; }
// Call the syssetup function to reset the display.
//
return SetupSetDisplay(lpStateData->lpszWinBOMPath, WBOM_SETTINGS_SECTION, WBOM_SETTINGS_DISPLAY, WBOM_SETTINGS_REFRESH, WBOM_SETTINGS_DISPLAY_MINWIDTH, WBOM_SETTINGS_DISPLAY_MINHEIGHT, WBOM_SETTINGS_DISPLAY_MINDEPTH); }
static HANDLE WaitForOpenEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName, DWORD dwMilliseconds) { HANDLE hEvent; DWORD dwTime = 0, dwSleep = 100; BOOL bBail = (0 == dwMilliseconds);
// Keep looping until we get an event handle or we time out.
//
while ( ( NULL == (hEvent = OpenEvent(dwDesiredAccess, bInheritHandle, lpName)) ) && !bBail ) { // Only bother to test for the time out if they didn't
// pass in infinite.
//
if ( INFINITE != dwMilliseconds ) { // Add our sleep interval and make sure we will not
// go over out limit.
//
dwTime += dwSleep; if ( dwTime >= dwMilliseconds ) { // If we will go over, caclculate how much
// time we have left to sleep (it must be less
// than our normal interval) and set the flag
// so we stop trying after the next try.
//
dwSleep = dwMilliseconds - (dwTime - dwSleep); bBail = TRUE; } }
// Now sleep for our interval or less (should never
// be zero, but doesn't really matter if it is).
//
Sleep(dwSleep); }
// If we are failing and we timed out, we need to set
// the last error (if we didn't time out the error will
// already be set by OpenEvent).
//
if ( ( NULL == hEvent ) && bBail ) SetLastError(WAIT_TIMEOUT);
// Return the event handle.
//
return hEvent; }
|