windows-nt/Source/XPSP1/NT/inetsrv/query/web/ixsso/ixserror.cxx
2020-09-26 16:20:57 +08:00

363 lines
11 KiB
C++

//+---------------------------------------------------------------------------
//
// Copyright (C) 1997-1998, Microsoft Corporation.
//
// File: ixserror.cxx
//
// Contents: SSO Error class
//
// History: 04 Apr 1997 Alanw Created
//
//----------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
//-----------------------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------------------
// debugging macros
#include "ssodebug.hxx"
// class declaration
#include "ixserror.hxx"
//-----------------------------------------------------------------------------
//
// Member: CixssoError::SetError - private
//
// Synopsis: Save error information
//
// Arguments: [scError] - Error code
// [iLine] - (optional) line number where error occurred
// [pwszFile] - (optional) file name where error occurred
// [pwszLoc] - Location from which error was generated
// [eErrClass] - error class, indicates error message file
//
// Notes:
//
// History: 07 Jan 1997 Alanw Created
//
//-----------------------------------------------------------------------------
extern HINSTANCE g_hInst;
extern WCHAR * g_pwszErrorMsgFile;
#define ERROR_MESSAGE_SIZE 512
void CixssoError::SetError(
SCODE scError,
ULONG iLine,
WCHAR const * pwszFile,
WCHAR const * pwszLoc,
unsigned eErrClass,
LCID lcid)
{
// Has the error already been handled? If so, return.
if ( _sc != 0)
return;
if ( QUERY_E_DUPLICATE_OUTPUT_COLUMN == scError )
{
scError = MSG_IXSSO_DUPLICATE_COLUMN;
eErrClass = eIxssoError;
}
else if ( QUERY_E_INVALID_OUTPUT_COLUMN == scError )
{
scError = MSG_IXSSO_NO_SUCH_COLUMN_PROPERTY;
eErrClass = eIxssoError;
}
// Does this error (possibly transalted) already exist on the error stack?
// If it does, and it has a description, we shouldn't be doing anything else.
if (FALSE == NeedToSetError(scError))
return;
ixssoDebugOut(( DEB_ITRACE, "SetError: sc = %x, loc = %ws\n", scError, pwszLoc ));
WCHAR awcsErrorMessage[ERROR_MESSAGE_SIZE];
WCHAR *pwszErrorMessage = awcsErrorMessage;
ULONG cchAvailMessage = ERROR_MESSAGE_SIZE;
//
// Generate the Win32 error code by removing the facility code (7) and
// the error bit.
//
ULONG Win32status = scError;
if ( (Win32status & (FACILITY_WIN32 << 16)) == (FACILITY_WIN32 << 16) )
{
Win32status &= ~( 0x80000000 | (FACILITY_WIN32 << 16) );
}
//
// Don't pass a specific lang id to FormatMessage since it will
// fail if there's no message in that language. Instead set
// the thread locale, which will get FormatMessage to use a search
// algorithm to find a message of the appropriate language or
// use a reasonable fallback msg if there's none.
//
LCID SaveLCID = GetThreadLocale();
SetThreadLocale(lcid);
// Precede the error message by the file/line if passed.
if (pwszFile != 0)
{
UINT_PTR args [] = {
(UINT_PTR) pwszFile,
(UINT_PTR) iLine,
};
NTSTATUS MsgNum = MSG_IXSSO_FILE_MESSAGE;
if (iLine != 0)
{
MsgNum = MSG_IXSSO_FILE_LINE_MESSAGE;
}
ULONG cchMsg = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
g_hInst,
MsgNum,
0,
pwszErrorMessage,
cchAvailMessage,
(va_list *) args );
pwszErrorMessage += cchMsg;
cchAvailMessage -= cchMsg;
}
BOOL fSystemError = FALSE;
switch (eErrClass)
{
case eIxssoError:
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
g_hInst,
scError,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) )
{
ixssoDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage,
L"Error 0x%x caught while processing query\n",
scError );
}
break;
case ePlistError:
case eParseError:
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(g_pwszErrorMsgFile),
scError,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) )
{
ixssoDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage,
L"Error 0x%x caught while parsing query or other fields\n",
scError );
}
break;
case eDefaultError:
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
g_hInst,
scError,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) )
{
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(g_pwszErrorMsgFile),
scError,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) )
{
//
// Try looking up the error in the Win32 list of error codes
//
if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(L"kernel32.dll"),
Win32status,
0,
pwszErrorMessage,
cchAvailMessage,
0 ) )
{
ixssoDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
swprintf( pwszErrorMessage,
L"Error 0x%x caught while processing query\n",
scError );
}
else
{
fSystemError = TRUE;
}
}
}
break;
default:
Win4Assert( !"Unrecognized error class" );
break;
}
SetThreadLocale(SaveLCID);
SetError( scError, pwszLoc, awcsErrorMessage );
}
//-----------------------------------------------------------------------------
//
// Member: CixssoError::SetError - private
//
// Synopsis: Save error information
//
// Arguments: [scError] - Error code
// [pwszLoc] - Location from which error was generated
// [pwszDescription] - Error description
//
// Notes:
//
// History: 06 May 1997 KrishnaN Created
//
//-----------------------------------------------------------------------------
void CixssoError::SetError( SCODE scError,
WCHAR const * pwszLoc,
WCHAR const * pwszDescription)
{
// Has the error on this object already been set?
if (_sc != 0)
return;
// We should be here only if an error has NOT already been set.
Win4Assert(NeedToSetError(scError));
Win4Assert(pwszLoc && pwszDescription);
ixssoDebugOut(( DEB_ITRACE,
"SetError: sc = %x, loc = %ws,\n\tdescription = %ws\n",
scError, pwszLoc, pwszDescription ));
_fErr = TRUE;
_sc = scError;
//
// Create an error info object giving the error message
//
ICreateErrorInfo * pErrorInfo;
SCODE sc = CreateErrorInfo( &pErrorInfo );
if (SUCCEEDED( sc ))
{
XInterface<ICreateErrorInfo> pErr(pErrorInfo);
pErrorInfo = 0;
pErr->SetDescription( (LPWSTR) pwszDescription );
pErr->SetGUID( _iid );
pErr->SetSource( (LPWSTR) pwszLoc ); // Cast ok. Never touched by anyone.
IErrorInfo * pErrInfo = 0;
sc = pErr->QueryInterface( IID_IErrorInfo, (void **)&pErrInfo);
if (SUCCEEDED(sc))
{
SetErrorInfo(0, pErrInfo);
pErrInfo->Release();
}
}
}
//-----------------------------------------------------------------------------
//
// Member: CixssoError::NeedToSetError - private
//
// Synopsis: Determine if error needs to be set.
//
// Arguments: [scError] - Error code to look for
//
// Returns: TRUE if the error needs to be set. FALSE, if it already
// exists and has a valid description string.
//
// Notes:
//
// History: 15 Jan 1998 KrishnaN Created
//
//-----------------------------------------------------------------------------
BOOL CixssoError::NeedToSetError(SCODE scError)
{
BOOL fFound = FALSE;
//
// Get the current error object. Return TRUE if none exists.
//
XInterface<IErrorInfo> xErrorInfo;
SCODE sc = GetErrorInfo(0, (IErrorInfo **)xErrorInfo.GetQIPointer());
if ( S_FALSE == sc )
{
Win4Assert(0 == xErrorInfo.GetPointer());
return TRUE;
}
// Get the IErrorRecord interface and get the count of errors.
XInterface<IErrorRecords> xErrorRecords;
XBStr xDescription;
BSTR pDescription = xDescription.GetPointer();
sc = xErrorInfo->QueryInterface(IID_IErrorRecords, xErrorRecords.GetQIPointer());
if (0 == xErrorRecords.GetPointer())
{
// No error records. Do we at least have the top level description set?
// If so, that indicates an automation client called SetErrorInfo before us
// and we should not overwrite them.
xErrorInfo->GetDescription(&pDescription);
fFound = ( pDescription != 0 ) ;
}
else
{
ULONG cErrRecords;
sc = xErrorRecords->GetRecordCount(&cErrRecords);
Win4Assert(!fFound);
// look for the target error code. stop when one is found
ERRORINFO ErrorInfo;
for (ULONG i = 0; i < cErrRecords; i++)
{
sc = xErrorRecords->GetBasicErrorInfo(i, &ErrorInfo);
Win4Assert(S_OK == sc);
if (scError == ErrorInfo.hrError)
{
xErrorInfo->GetDescription(&pDescription);
fFound = ( pDescription != 0 );
break;
}
}
}
if (!fFound)
return TRUE;
// we found the error code and it has a description.
// no need to set this error again, but we have to
// put this error info back so the client can find it.
SetErrorInfo(0, xErrorInfo.GetPointer());
return FALSE;
}