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.
631 lines
22 KiB
631 lines
22 KiB
/*++
|
|
|
|
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;
|
|
}
|