mirror of https://github.com/tongzx/nt5src
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.
1265 lines
34 KiB
1265 lines
34 KiB
//
|
|
// MODULE: TSMapClient.cpp
|
|
//
|
|
// PURPOSE: Part of launching a Local Troubleshooter from an arbitrary NT5 application
|
|
// Class TSMapClient is available at runtime for mapping from the application's
|
|
// way of naming a problem to the Troubleshooter's way.
|
|
// Only a single thread should operate on any one object of class TSMapClient. The object is not
|
|
// threadsafe.
|
|
// In addition to the overtly noted returns, many methods can return a preexisting error.
|
|
// However, if the calling program has wishes to ignore an error and continue, we
|
|
// recommend an explicit call to inherited method ClearStatus().
|
|
// Note that the mapping file is always strictly SBCS (Single Byte Character Set), but the
|
|
// calls into this code may use Unicode. This file consequently mixes char and TCHAR.
|
|
//
|
|
// COMPANY: Saltmine Creative, Inc. (206)-633-4743 [email protected]
|
|
//
|
|
// AUTHOR: Joe Mabel
|
|
//
|
|
// ORIGINAL DATE: 2-26-98
|
|
//
|
|
//
|
|
// Version Date By Comments
|
|
//--------------------------------------------------------------------
|
|
// V0.1 - JM Original
|
|
///////////////////////
|
|
|
|
|
|
// TSMapClient
|
|
//
|
|
// AUTHOR: Joe Mabel
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "TSLError.h"
|
|
#include "RSSTACK.H"
|
|
#include "TSMapAbstract.h"
|
|
#include "TSMap.h"
|
|
#include "TSMapClient.h"
|
|
|
|
// uncomment the following line to turn on Joe's hard-core debugging
|
|
//#define KDEBUG 1
|
|
#ifdef KDEBUG
|
|
static HANDLE hDebugFile = INVALID_HANDLE_VALUE;
|
|
static DWORD dwBytesWritten;
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
|
|
// because the null string is a perfectly valid value for some strings, we reserve an
|
|
// arbitrary implausible value so we don't get a false cache match on startup.
|
|
const char * const szBogus = "**BOGUS**";
|
|
|
|
// Convert TCHAR *szt to char *sz. *sz should point to a big enough buffer
|
|
// to contain an SNCS version of *szt. count indicates the size of buffer *sz.
|
|
// returns sz (convenient for use in string functions).
|
|
static char* ToSBCS (char * const sz, const TCHAR * szt, size_t count)
|
|
{
|
|
if (sz)
|
|
{
|
|
if (count != 0 && !szt)
|
|
sz[0] = '\0';
|
|
else
|
|
{
|
|
#ifdef _UNICODE
|
|
wcstombs( sz, szt, count );
|
|
#else
|
|
strcpy(sz, szt);
|
|
#endif
|
|
}
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
// Convert char *sz to TCHAR *szt. *szt should point to a big enough buffer
|
|
// to contain a TCHAR* version of *sz (twice as big if its Unicode).
|
|
// count indicates the size of buffer *szt.
|
|
// returns szt (convenient for use in string functions).
|
|
static TCHAR* FromSBCS (TCHAR * const szt, const char * const sz, size_t count)
|
|
{
|
|
if (szt)
|
|
{
|
|
if (count != 0 && !sz)
|
|
szt[0] = _T('\0');
|
|
else
|
|
{
|
|
#ifdef _UNICODE
|
|
mbstowcs( szt, sz, count);
|
|
#else
|
|
strcpy(szt, sz);
|
|
#endif
|
|
}
|
|
}
|
|
return szt;
|
|
}
|
|
|
|
TSMapClient::TSMapClient(const TCHAR * const sztMapFile)
|
|
{
|
|
TSMapRuntimeAbstract::TSMapRuntimeAbstract();
|
|
_tcscpy(m_sztMapFile, sztMapFile);
|
|
m_hMapFile = INVALID_HANDLE_VALUE;
|
|
|
|
// >>> 1/16/98 we are setting these false until we can arrange to use the same'
|
|
// collating sequence in SQL Server & in this code.
|
|
m_bAppAlphaOrder = false;
|
|
m_bVerAlphaOrder = false;
|
|
m_bDevIDAlphaOrder = false;
|
|
m_bDevClassGUIDAlphaOrder = false;
|
|
m_bProbAlphaOrder = false;
|
|
|
|
Initialize();
|
|
ClearAll();
|
|
}
|
|
|
|
TSMapClient::~TSMapClient()
|
|
{
|
|
if (m_hMapFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(m_hMapFile);
|
|
}
|
|
|
|
// If not already initialized, open the mapping file & read the header
|
|
// Note that this is not thread-safe. Only a single thread should use a given TSMapClient
|
|
// object.
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// Typically, on entry m_dwStatus should be 0 and will be left alone if there are no errors
|
|
// Can set m_dwStatus to any of the following values:
|
|
// TSL_ERROR_MAP_CANT_OPEN_MAP_FILE
|
|
// TSL_ERROR_MAP_BAD_HEAD_MAP_FILE
|
|
DWORD TSMapClient::Initialize()
|
|
{
|
|
static bool bInit = false;
|
|
DWORD dwStatus = 0;
|
|
|
|
if (!bInit)
|
|
{
|
|
m_hMapFile = CreateFile(
|
|
m_sztMapFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL, // no security attributes
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS,
|
|
NULL // handle to template file
|
|
);
|
|
|
|
if (m_hMapFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
dwStatus = TSL_ERROR_MAP_CANT_OPEN_MAP_FILE;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwBytesRead;
|
|
|
|
if (!Read( &m_header, sizeof(m_header), &dwBytesRead))
|
|
dwStatus = TSL_ERROR_MAP_BAD_HEAD_MAP_FILE;
|
|
}
|
|
|
|
if (dwStatus)
|
|
m_dwStatus = dwStatus;
|
|
else
|
|
bInit = true;
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// This function sets us back to a starting state, but has no effect on the mapping
|
|
// file. It should succeed unless we've encountered a "hard" error, which would indicate
|
|
// a bug either in the code or in the mapping file. Note that it wipes out the caching.
|
|
// If you want ot leave caching intact, just call inherited method ClearStatus().
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class. returned value is either 0 or a _preexisting_ hard error we can't clear.
|
|
DWORD TSMapClient::ClearAll ()
|
|
{
|
|
if (!HardMappingError(m_dwStatus))
|
|
{
|
|
ClearStatus();
|
|
TSMapRuntimeAbstract::ClearAll();
|
|
|
|
strcpy(m_szApp, szBogus);
|
|
strcpy(m_appmap.szMapped, szBogus);
|
|
strcpy(m_szVer, szBogus);
|
|
strcpy(m_vermap.szMapped, szBogus);
|
|
strcpy(m_szDevID, szBogus);
|
|
m_uidDev = uidNil;
|
|
strcpy(m_szDevClassGUID, szBogus);
|
|
m_uidDevClass = uidNil;
|
|
strcpy(m_szProb, szBogus);
|
|
m_uidProb = uidNil;
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Get information about an application (input sztApp) from the mapping file into m_appmap
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS: 0 or TSL_ERROR_UNKNOWN_APP.
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::SetApp (const TCHAR * const sztApp)
|
|
{
|
|
char szApp[BUFSIZE];
|
|
bool bFound = false;
|
|
|
|
ToSBCS (szApp, sztApp, BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( strcmp(szApp, m_szApp) )
|
|
{
|
|
// it's not already in the cache; let's try to load it.
|
|
int cmp = 1; // in alpha order, it's still ahead
|
|
DWORD dwPosition;
|
|
bool bFirstTime = true;
|
|
|
|
dwPosition = m_header.dwOffApp;
|
|
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFound
|
|
&& dwPosition < m_header.dwLastOffApp
|
|
&& ! (cmp < 0 && m_bAppAlphaOrder) )
|
|
{
|
|
if (ReadAppMap (m_appmap, dwPosition, bFirstTime) )
|
|
{
|
|
cmp = strcmp(szApp, m_appmap.szMapped);
|
|
bFound = ( cmp == 0 );
|
|
}
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if (bFound)
|
|
{
|
|
strcpy( m_szApp, szApp );
|
|
// Different application invalidates the version
|
|
strcpy( m_szVer, szBogus );
|
|
}
|
|
else
|
|
m_dwStatus = TSL_ERROR_UNKNOWN_APP;
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Get information about a version (input sztVer) from the mapping file into m_vermap.
|
|
// A version makes sense only in the context of an application.
|
|
// The null string is a valid input value and corresponds to leaving version blank.
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSM_STAT_NEED_APP_TO_SET_VER
|
|
// TSL_ERROR_UNKNOWN_VER
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::SetVer (const TCHAR * const sztVer)
|
|
{
|
|
char szVer[BUFSIZE];
|
|
bool bFound = false;
|
|
|
|
ToSBCS (szVer, sztVer, BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( !strcmp(m_szApp, szBogus) )
|
|
{
|
|
m_dwStatus = TSM_STAT_NEED_APP_TO_SET_VER;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
if (strcmp(m_szVer, szVer) )
|
|
{
|
|
// it's not already in the cache; let's try to load it.
|
|
int cmp = 1; // in alpha order, it's still ahead
|
|
DWORD dwPosition;
|
|
bool bFirstTime = true;
|
|
|
|
dwPosition = m_appmap.dwOffVer;
|
|
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFound
|
|
&& dwPosition < m_appmap.dwLastOffVer
|
|
&& ! (cmp < 0 && m_bVerAlphaOrder) )
|
|
{
|
|
if (ReadVerMap (m_vermap, dwPosition, bFirstTime) )
|
|
{
|
|
cmp = strcmp(szVer, m_vermap.szMapped);
|
|
bFound = ( cmp == 0 );
|
|
}
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if (bFound)
|
|
strcpy( m_szVer, szVer );
|
|
else
|
|
m_dwStatus = TSL_ERROR_UNKNOWN_VER;
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// INPUT sztProb should be either a problem name or represent a number < 2**16. In the
|
|
// former case, we look up the UID in the mapping file. In the latter
|
|
// case, we just translate it to a number to get a problem UID.
|
|
// The null string is a valid input value and corresponds to leaving version blank. Only
|
|
// makes sense if there is a device (or device class) specified before we try to launch.
|
|
// Sets m_uidProb, m_szProb
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_WARNING_UNKNOWN_APPPROBLEM - This is not necessarily bad, and results in setting
|
|
// m_uidProb = uidNil
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::SetProb (const TCHAR * const sztProb)
|
|
{
|
|
char szProb[BUFSIZE];
|
|
bool bIsNumber = true;
|
|
|
|
ToSBCS (szProb, sztProb, BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
// Null string is not a number; any string with a non-digit in it is not a number
|
|
if (szProb[0] == '\0')
|
|
bIsNumber = false;
|
|
else
|
|
{
|
|
int i = 0;
|
|
while (szProb[i] != '\0')
|
|
if (! isdigit(szProb[i]))
|
|
{
|
|
bIsNumber = false;
|
|
break;
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
|
|
if (bIsNumber)
|
|
m_uidProb = atoi(szProb);
|
|
else if ( strcmp(szProb, m_szProb) )
|
|
{
|
|
// it's not already in the cache; let's try to load it.
|
|
m_uidProb = GetGenericMapToUID(sztProb,
|
|
m_header.dwOffProb, m_header.dwLastOffProb, m_bProbAlphaOrder);
|
|
|
|
if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
|
|
m_dwStatus = TSL_WARNING_UNKNOWN_APPPROBLEM;
|
|
|
|
if (m_uidProb != uidNil)
|
|
strcpy( m_szProb, szProb );
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Get information about a device (input sztDevID) from the mapping file into m_appmap.
|
|
// The null string is a valid input value and corresponds to no specified device.
|
|
// Except for Device Manager, this is typical usage.
|
|
// Sets m_uidDev, m_szDev
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_WARNING_BAD_DEV_ID - This is not necessarily bad, and results in setting
|
|
// m_uidDev = uidNil
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::SetDevID (const TCHAR * const sztDevID)
|
|
{
|
|
char szDevID[BUFSIZE];
|
|
|
|
ToSBCS (szDevID, sztDevID, BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( strcmp(szDevID, m_szDevID) )
|
|
{
|
|
// it's not already in the cache; let's try to load it.
|
|
m_uidDev = GetGenericMapToUID (sztDevID,
|
|
m_header.dwOffDevID, m_header.dwLastOffDevID, m_bDevIDAlphaOrder);
|
|
|
|
if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
|
|
m_dwStatus = TSL_WARNING_BAD_DEV_ID;
|
|
|
|
if (m_uidDev != uidNil)
|
|
strcpy( m_szDevID, szDevID );
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Get information about a device class (input sztDevClassGUID) from the mapping file
|
|
// into m_appmap.
|
|
// The null string is a valid input value and corresponds to no specified device.
|
|
// Except for Device Manager, this is typical usage.
|
|
// Sets m_uidDevClass, m_szDevClass
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_WARNING_BAD_CLASS_GUID - This is not necessarily bad, and results in setting
|
|
// m_uidDevClass = uidNil
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::SetDevClassGUID (const TCHAR * const sztDevClassGUID)
|
|
{
|
|
char szDevClassGUID[BUFSIZE];
|
|
|
|
ToSBCS (szDevClassGUID, sztDevClassGUID, BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( strcmp(szDevClassGUID, m_szDevClassGUID) )
|
|
{
|
|
// it's not already in the cache; let's try to load it.
|
|
m_uidDevClass = GetGenericMapToUID (sztDevClassGUID,
|
|
m_header.dwOffDevClass, m_header.dwLastOffDevClass, m_bDevClassGUIDAlphaOrder);
|
|
|
|
if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
|
|
m_dwStatus = TSL_WARNING_BAD_CLASS_GUID;
|
|
|
|
if (m_uidDevClass != uidNil)
|
|
strcpy( m_szDevClassGUID, szDevClassGUID );
|
|
}
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Set troubleshooter (& possibly problem node) on the basis of application, version,
|
|
// problem (ignoring device information). This is achieved by a lookup in the mapping file
|
|
// on the basis of previously set member values of this object.
|
|
// "TSBN" means "Troubleshooter Belief Network"
|
|
// On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
|
|
// OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
|
|
// the problem page of the TSBN with no problem selected.
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_ERROR_NO_NETWORK - Mapping failed
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::FromProbToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
|
|
{
|
|
char szTSBN[BUFSIZE];
|
|
char szNode[BUFSIZE];
|
|
|
|
FromSBCS (sztTSBN, "", BUFSIZE);
|
|
FromSBCS (sztNode, "", BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( m_uidProb == uidNil )
|
|
{
|
|
// Can't do this if m_uidProb is NIL
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
DWORD dwPosition;
|
|
bool bFirstTime = true;
|
|
bool bFound = false;
|
|
PROBMAP probmap;
|
|
|
|
dwPosition = m_vermap.dwOffProbUID;
|
|
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFound
|
|
&& dwPosition < m_vermap.dwLastOffProbUID )
|
|
{
|
|
if ( ReadProbMap (probmap, dwPosition, bFirstTime) )
|
|
{
|
|
bFound = ( probmap.uidProb == m_uidProb );
|
|
}
|
|
|
|
if (probmap.uidProb > m_uidProb)
|
|
break; // we're past it. No hit.
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if (bFound)
|
|
{
|
|
strcpy( szNode, probmap.szProblemNode );
|
|
if (! ReadString (szTSBN, BUFSIZE, probmap.dwOffTSName, TRUE) )
|
|
{
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
}
|
|
}
|
|
else
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
|
|
FromSBCS (sztTSBN, szTSBN, BUFSIZE);
|
|
FromSBCS (sztNode, szNode, BUFSIZE);
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Set troubleshooter (& possibly problem node) on the basis of application, version, device
|
|
// and (optionally) problem. This is achieved by a lookup in the mapping file on the basis
|
|
// of previously set member values of this object.
|
|
// "TSBN" means "Troubleshooter Belief Network"
|
|
// On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
|
|
// OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
|
|
// the problem page of the TSBN with no problem selected.
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_ERROR_NO_NETWORK - Mapping failed
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::FromDevToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
|
|
{
|
|
char szTSBN[BUFSIZE];
|
|
char szNode[BUFSIZE];
|
|
|
|
FromSBCS (sztTSBN, "", BUFSIZE);
|
|
FromSBCS (sztNode, "", BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( m_uidDev == uidNil )
|
|
{
|
|
// Can't do this if m_uidDev is NIL
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
DWORD dwPosition;
|
|
bool bFirstTime = true;
|
|
bool bFoundDev = false;
|
|
bool bFoundProb = false;
|
|
DEVMAP devmap;
|
|
|
|
dwPosition = m_vermap.dwOffDevUID;
|
|
|
|
// Look in the version-specific list of device-mappings, till we find the right device.
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFoundDev
|
|
&& dwPosition < m_vermap.dwLastOffDevUID )
|
|
{
|
|
if ( ReadDevMap (devmap, dwPosition, bFirstTime) )
|
|
{
|
|
bFoundDev = ( devmap.uidDev == m_uidDev );
|
|
}
|
|
|
|
if (devmap.uidDev > m_uidDev)
|
|
break; // we're past it. No hit.
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if ( bFoundDev )
|
|
{
|
|
// The very first one might be the right problem, or we might have to scan through
|
|
// several mappings for this device before we get the right problem.
|
|
bFoundProb = ( devmap.uidDev == m_uidDev && devmap.uidProb == m_uidProb );
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFoundProb
|
|
&& dwPosition < m_vermap.dwLastOffDevUID )
|
|
{
|
|
if ( ReadDevMap (devmap, dwPosition ) )
|
|
{
|
|
bFoundProb = ( devmap.uidDev == m_uidDev && devmap.uidProb == m_uidProb );
|
|
}
|
|
|
|
if ( devmap.uidDev > m_uidDev || devmap.uidProb > m_uidProb )
|
|
break; // we're past it. No hit.
|
|
}
|
|
}
|
|
|
|
if (bFoundProb)
|
|
{
|
|
strcpy( szNode, devmap.szProblemNode );
|
|
if (! ReadString (szTSBN, BUFSIZE, devmap.dwOffTSName, TRUE) )
|
|
{
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
}
|
|
}
|
|
else
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
|
|
FromSBCS (sztTSBN, szTSBN, BUFSIZE);
|
|
FromSBCS (sztNode, szNode, BUFSIZE);
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Set troubleshooter (& possibly problem node) on the basis of application, version, device
|
|
// class and (optionally) problem. This is achieved by a lookup in the mapping file on
|
|
// the basis of previously set member values of this object.
|
|
// "TSBN" means "Troubleshooter Belief Network"
|
|
// On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
|
|
// OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
|
|
// the problem page of the TSBN with no problem selected.
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_ERROR_NO_NETWORK - Mapping failed
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
// >>> There is probably some way to share common code with FromDevToTS()
|
|
DWORD TSMapClient::FromDevClassToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
|
|
{
|
|
char szTSBN[BUFSIZE];
|
|
char szNode[BUFSIZE];
|
|
|
|
FromSBCS (sztTSBN, "", BUFSIZE);
|
|
FromSBCS (sztNode, "", BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
#ifdef KDEBUG
|
|
char* szStart = "START\n";
|
|
char* szEnd = "END\n";
|
|
char sz[150];
|
|
hDebugFile = CreateFile(
|
|
(m_uidProb == uidNil) ? _T("k0debug.txt") : _T("k1debug.txt"),
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
WriteFile(
|
|
hDebugFile,
|
|
szStart,
|
|
strlen(szStart),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
sprintf (sz, "look for DevClassUID %d, ProbUID %d\n", m_uidDevClass, m_uidProb);
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
|
|
if ( m_uidDevClass == uidNil )
|
|
{
|
|
// Can't do this if m_uidDevClass is NIL
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
DWORD dwPosition;
|
|
bool bFirstTime = true;
|
|
bool bFoundDevClass = false;
|
|
bool bFoundProb = false;
|
|
DEVCLASSMAP devclassmap;
|
|
|
|
dwPosition = m_vermap.dwOffDevClassUID;
|
|
|
|
// Look in the version-specific list of device-class-mappings, till we find the right device class.
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFoundDevClass
|
|
&& dwPosition < m_vermap.dwLastOffDevClassUID )
|
|
{
|
|
if ( ReadDevClassMap (devclassmap, dwPosition, bFirstTime) )
|
|
{
|
|
bFoundDevClass = ( devclassmap.uidDevClass == m_uidDevClass );
|
|
}
|
|
|
|
if (devclassmap.uidDevClass > m_uidDevClass)
|
|
break; // we're past it. No hit.
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if ( bFoundDevClass )
|
|
{
|
|
#ifdef KDEBUG
|
|
sprintf (sz, "found DevClassUID %d w/ ProbUID %d\n", m_uidDevClass, devclassmap.uidProb);
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
// The very first one might be the right problem, or we might have to scan through
|
|
// several mappings for this device class before we get the right problem.
|
|
bFoundProb = ( devclassmap.uidDevClass == m_uidDevClass && devclassmap.uidProb == m_uidProb );
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFoundProb
|
|
&& dwPosition < m_vermap.dwLastOffDevClassUID )
|
|
{
|
|
if ( ReadDevClassMap (devclassmap, dwPosition) )
|
|
{
|
|
bFoundProb = ( devclassmap.uidDevClass == m_uidDevClass && devclassmap.uidProb == m_uidProb );
|
|
}
|
|
|
|
if ( devclassmap.uidDevClass > m_uidDevClass || devclassmap.uidProb > m_uidProb )
|
|
break; // we're past it. No hit.
|
|
|
|
#ifdef KDEBUG
|
|
sprintf (sz, "found DevClassUID %d w/ ProbUID %d\n", m_uidDevClass, devclassmap.uidProb);
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
if (bFoundProb)
|
|
{
|
|
#ifdef KDEBUG
|
|
sprintf (sz, "found right problem");
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
strcpy( szNode, devclassmap.szProblemNode );
|
|
if (! ReadString (szTSBN, BUFSIZE, devclassmap.dwOffTSName, TRUE) )
|
|
{
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
#ifdef KDEBUG
|
|
sprintf (sz, ", but can't read its name\n");
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef KDEBUG
|
|
sprintf (sz, ": net [%s] node [%s]\n", szTSBN, szNode);
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwStatus = TSL_ERROR_NO_NETWORK;
|
|
#ifdef KDEBUG
|
|
sprintf (sz, "No match");
|
|
WriteFile(
|
|
hDebugFile,
|
|
sz,
|
|
strlen(sz),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
#endif
|
|
}
|
|
|
|
FromSBCS (sztTSBN, szTSBN, BUFSIZE);
|
|
FromSBCS (sztNode, szNode, BUFSIZE);
|
|
|
|
return m_dwStatus;
|
|
#ifdef KDEBUG
|
|
CloseHandle(hDebugFile);
|
|
hDebugFile = INVALID_HANDLE_VALUE;
|
|
#endif
|
|
}
|
|
|
|
// To be used after we have failed to find a mapping for the currently selected version.
|
|
// Each version can specify a version to try as a default, including the "blank" version,
|
|
// which is distinct from "no version".
|
|
// The last version in a chain of defaults will "default" to uidNil: "no version".
|
|
// Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
|
|
// parent class.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_WARNING_END_OF_VER_CHAIN - OK, but there's nothing to default to.
|
|
// TSM_STAT_NEED_APP_TO_SET_VER
|
|
// TSM_STAT_NEED_VER_TO_SET_VER - there was no version set, so no basis for a default
|
|
// TSL_ERROR_UNKNOWN_VER
|
|
// Can also return hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or preexisting hard error)
|
|
DWORD TSMapClient::ApplyDefaultVer()
|
|
{
|
|
bool bFound = false;
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
if ( !strcmp(m_szApp, szBogus) )
|
|
{
|
|
m_dwStatus = TSM_STAT_NEED_APP_TO_SET_VER;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
if ( !strcmp(m_szVer, szBogus) )
|
|
{
|
|
m_dwStatus = TSM_STAT_NEED_VER_TO_SET_DEF_VER;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
DWORD dwPosition;
|
|
bool bFirstTime = true;
|
|
UID uidDefault = m_vermap.uidDefault;
|
|
|
|
if (uidDefault == uidNil)
|
|
{
|
|
m_dwStatus = TSL_WARNING_END_OF_VER_CHAIN;
|
|
return m_dwStatus;
|
|
}
|
|
|
|
dwPosition = m_appmap.dwOffVer;
|
|
|
|
while (
|
|
!m_dwStatus
|
|
&& !bFound
|
|
&& dwPosition < m_appmap.dwLastOffVer )
|
|
{
|
|
if (ReadVerMap (m_vermap, dwPosition, bFirstTime) )
|
|
{
|
|
bFound = ( m_vermap.uid == uidDefault );
|
|
}
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if (bFound)
|
|
strcpy( m_szVer, m_vermap.szMapped );
|
|
else
|
|
m_dwStatus = TSL_ERROR_UNKNOWN_VER;
|
|
|
|
return m_dwStatus;
|
|
}
|
|
|
|
// Within a particular range of the mapping file, read UIDMAP records to try to map from
|
|
// input sztName to a UID.
|
|
// Return resulting UID, including possibly UidNil
|
|
// Sets m_dwStatus, which can be obtained via GetStatus(), inherited from the parent class.
|
|
// Can set m_dwStatus to:
|
|
// 0 - OK
|
|
// TSM_STAT_UID_NOT_FOUND
|
|
// Can also set m_dwStatus to hard errors:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// (or may be left reflecting a preexisting hard error)
|
|
UID TSMapClient::GetGenericMapToUID (const TCHAR * const sztName,
|
|
DWORD dwOffFirst, DWORD dwOffLast,
|
|
bool bAlphaOrder)
|
|
{
|
|
char szName[BUFSIZE];
|
|
DWORD dwPosition;
|
|
UIDMAP uidmap;
|
|
bool bFirstTime = true;
|
|
bool bFound = false;
|
|
|
|
ToSBCS (szName, sztName, BUFSIZE);
|
|
|
|
if (HardMappingError(m_dwStatus))
|
|
return m_dwStatus;
|
|
else
|
|
ClearStatus();
|
|
|
|
dwPosition = dwOffFirst;
|
|
|
|
while ( !m_dwStatus && !bFound && dwPosition < dwOffLast)
|
|
{
|
|
if (ReadUIDMap (uidmap, dwPosition, bFirstTime) )
|
|
{
|
|
int cmp = strcmp(szName, uidmap.szMapped);
|
|
bFound = ( cmp == 0 );
|
|
if ( cmp < 0 && bAlphaOrder )
|
|
// relying here on alphabetical order; we've passed what we're looking for
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
m_dwStatus = TSM_STAT_UID_NOT_FOUND;
|
|
}
|
|
|
|
bFirstTime = false;
|
|
}
|
|
|
|
if (bFound)
|
|
return uidmap.uid;
|
|
else
|
|
{
|
|
m_dwStatus = TSM_STAT_UID_NOT_FOUND;
|
|
return uidNil;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------- utility functions ------------------------
|
|
// I/O, wrapped the way we are using it.
|
|
|
|
// SetFilePointerAbsolute sets map file to a location & returns that location if successful
|
|
// returns -1 and sets m_dwStatus on failure
|
|
// Sets m_dwStatus, which can be obtained via GetStatus(), inherited from the parent class.
|
|
// Although, in theory, a bad seek just indicates a bad dwMoveTo value, in practice
|
|
// a bad seek would indicate a serious problem either in the mapping file or in the calling
|
|
// function: we should only be seeking to offsets which the contents of the mapping file
|
|
// told us to seek to.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
DWORD TSMapClient::SetFilePointerAbsolute( DWORD dwMoveTo )
|
|
{
|
|
DWORD dwPosition = SetFilePointer(m_hMapFile, dwMoveTo, NULL, FILE_BEGIN);
|
|
|
|
if( dwPosition != dwMoveTo)
|
|
{
|
|
// >>> could call GetLastError, but what do we do with it?
|
|
m_dwStatus= TSL_ERROR_MAP_BAD_SEEK;
|
|
dwPosition = -1;
|
|
}
|
|
|
|
return dwPosition;
|
|
}
|
|
|
|
// Low-level read n bytes. Calls Win32 function ReadFile.
|
|
// Read from map file into lpBuffer
|
|
// returns true if requested # of bytes are read
|
|
// Returns false and sets m_dwStatus on failure
|
|
// Although, in theory, a bad read just indicates (for example) reading past EOF, in practice
|
|
// a bad read would indicate a serious problem either in the mapping file or in the calling
|
|
// function: we should only be reading (1) the header or (2) records which the contents of
|
|
// the mapping file told us to read.
|
|
// RETURNS:
|
|
// 0 - OK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
bool TSMapClient::Read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpdwBytesRead)
|
|
{
|
|
if (! ReadFile( m_hMapFile, lpBuffer, nNumberOfBytesToRead, lpdwBytesRead, NULL)
|
|
|| *lpdwBytesRead != nNumberOfBytesToRead )
|
|
{
|
|
// >>> On ReadFile returning false, could call GetLastError,
|
|
// but what do we do with it?
|
|
m_dwStatus= TSL_ERROR_MAP_BAD_READ;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Read a single UIDMAP from the mapping file (maps text to a UID)
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// OUTPUT uidmap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
bool TSMapClient::ReadUIDMap (UIDMAP &uidmap, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
DWORD dwBytesRead;
|
|
BOOL ret;
|
|
|
|
// First just read the byte count, then the rest
|
|
ret = Read( &uidmap, sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
// The first argument below may be a bit confusing. We take a pointer to
|
|
// the byte count (a short*) then increment it to point immediately past the
|
|
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
|
|
ret = Read( (&(uidmap.cb))+1, uidmap.cb - sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
dwPosition += uidmap.cb;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Read a single APPMAP from the mapping file (contains info about an application)
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// OUTPUT appmap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
bool TSMapClient::ReadAppMap (APPMAP &appmap, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
DWORD dwBytesRead;
|
|
BOOL ret;
|
|
|
|
// First just read the byte count, then the rest
|
|
ret = Read( &appmap, sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
// The first argument below may be a bit confusing. We take a pointer to
|
|
// the byte count (a short*) then increment it to point immediately past the
|
|
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
|
|
ret = Read( (&(appmap.cb))+1, appmap.cb - sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
dwPosition += appmap.cb;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Read a single VERMAP from the mapping file (contains info about a version)
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// OUTPUT vermap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
bool TSMapClient::ReadVerMap (VERMAP &vermap, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
DWORD dwBytesRead;
|
|
BOOL ret;
|
|
|
|
// First just read the byte count, then the rest
|
|
ret = Read( &vermap, sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
// The first argument below may be a bit confusing. We take a pointer to
|
|
// the byte count (a short*) then increment it to point immediately past the
|
|
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
|
|
ret = Read( (&(vermap.cb))+1, vermap.cb - sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
dwPosition += vermap.cb;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Read a single PROBMAP from the mapping file (contains a mapping for use by FromProbToTS())
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// OUTPUT vermap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
bool TSMapClient::ReadProbMap (PROBMAP &probmap, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
DWORD dwBytesRead;
|
|
BOOL ret;
|
|
|
|
// First just read the byte count, then the rest
|
|
ret = Read( &probmap, sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
// The first argument below may be a bit confusing. We take a pointer to
|
|
// the byte count (a short*) then increment it to point immediately past the
|
|
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
|
|
ret = Read( (&(probmap.cb))+1, probmap.cb - sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
dwPosition += probmap.cb;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Read a single DEVMAP from the mapping file (contains a mapping for use by FromDevToTS())
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// OUTPUT vermap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
bool TSMapClient::ReadDevMap (DEVMAP &devmap, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
DWORD dwBytesRead;
|
|
BOOL ret;
|
|
|
|
// First just read the byte count, then the rest
|
|
ret = Read( &devmap, sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
// The first argument below may be a bit confusing. We take a pointer to
|
|
// the byte count (a short*) then increment it to point immediately past the
|
|
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
|
|
ret = Read( (&(devmap.cb))+1, devmap.cb - sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
dwPosition += devmap.cb;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Read a single DEVCLASSMAP from the mapping file (contains a mapping for use by
|
|
// FromDevClassToTS())
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// OUTPUT vermap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// TSL_ERROR_MAP_BAD_READ
|
|
bool TSMapClient::ReadDevClassMap (DEVCLASSMAP &devclassmap, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
DWORD dwBytesRead;
|
|
BOOL ret;
|
|
|
|
// First just read the byte count, then the rest
|
|
ret = Read( &devclassmap, sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
// The first argument below may be a bit confusing. We take a pointer to
|
|
// the byte count (a short*) then increment it to point immediately past the
|
|
// byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
|
|
ret = Read( (&(devclassmap.cb))+1, devclassmap.cb - sizeof(short), &dwBytesRead);
|
|
if ( ret )
|
|
{
|
|
dwPosition += devclassmap.cb;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Low-level read a null-terminated string. Calls Win32 function ReadFile.
|
|
// If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
|
|
// Otherwise, dwPosition is assumed to be the correct file position at time of input.
|
|
// INPUT chMax is maximum # of bytes (not necessarily characters) to read. The last character
|
|
// will not actually be read: a null character will always be imposed.
|
|
// OUTPUT vermap
|
|
// RETURNS true on success
|
|
// On failure, returns false & sets m_dwStatus:
|
|
// TSL_ERROR_MAP_BAD_SEEK
|
|
// Note that on completion the file position is unreliable. It is based on the size of the
|
|
// buffer passed in, not the actual string.
|
|
bool TSMapClient::ReadString (char * sz, DWORD cbMax, DWORD &dwPosition, bool bSetPosition)
|
|
{
|
|
DWORD dwBytesRead;
|
|
|
|
|
|
|
|
if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
|
|
{
|
|
if (cbMax == 0)
|
|
return true;
|
|
|
|
if ( cbMax == 1 || ReadFile( m_hMapFile, sz, cbMax-1, &dwBytesRead, NULL) )
|
|
{
|
|
sz[cbMax-1] = '\0';
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Once one of these errors has occurred, we consider recovery impossible, except by closing
|
|
// this object and opening a new one.
|
|
// Although, in theory, a bad seek or read just indicates bad arguments
|
|
// to the relevant function, in practice a bad seek or read would indicate
|
|
// a serious problem either in the mapping file or in the calling
|
|
// function: beyond the header, we should only be seeking to and reading
|
|
// from offsets which the contents of the mapping file old us to seek/read.
|
|
bool TSMapClient::HardMappingError (DWORD dwStatus)
|
|
{
|
|
if (TSMapRuntimeAbstract::HardMappingError(dwStatus))
|
|
return true;
|
|
else
|
|
switch (dwStatus)
|
|
{
|
|
case TSL_ERROR_MAP_BAD_SEEK:
|
|
case TSL_ERROR_MAP_BAD_READ:
|
|
case TSL_ERROR_MAP_CANT_OPEN_MAP_FILE:
|
|
case TSL_ERROR_MAP_BAD_HEAD_MAP_FILE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|