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

974 lines
30 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000.
//
// File: main.cxx
//
// Contents: External entry points for idq.dll.
//
// History: 96/Jan/3 DwightKr Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <ntverp.h>
#define IDQ_VERSION 3
#define _DECL_DLLMAIN 1
CTheGlobalIDQVariables * pTheGlobalIDQVariables = 0;
DWORD g_cClients = 0;
CRITICAL_SECTION g_csInitExclusive;
//+---------------------------------------------------------------------------
//
// Function: GetExtensionVersion - public
//
// Synposis: Returns extension info to the server. This is called before
// HttpExtensionProc is called, and it is called in System
// context, so any initialization that requires this context
// must be handled here.
//
// Arguments: [pVer] - where the info goes
//
// History: 96-Apr-15 dlee Added header
//
// Notes: There may be multiple clients of this ISAPI app in one
// process (eg W3Svc and NNTPSvc), so refcount the users.
//
//----------------------------------------------------------------------------
BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO * pVer )
{
BOOL fSuccess = TRUE;
EnterCriticalSection( &g_csInitExclusive );
TRANSLATE_EXCEPTIONS;
TRY
{
pVer->dwExtensionVersion = MAKELONG( 0, IDQ_VERSION );
strcpy( pVer->lpszExtensionDesc, "Indexing Service extension" );
if ( 0 == g_cClients )
{
Win4Assert( 0 == pTheGlobalIDQVariables );
pTheGlobalIDQVariables = new CTheGlobalIDQVariables();
LoadServerErrors();
}
g_cClients++;
}
CATCH( CException, e )
{
fSuccess = FALSE;
ciGibDebugOut(( DEB_WARN, "GetExtensionVersion failed 0x%x\n",
e.GetErrorCode() ));
}
END_CATCH
UNTRANSLATE_EXCEPTIONS;
LeaveCriticalSection( &g_csInitExclusive );
return fSuccess;
} //GetExtensionVersion
//+---------------------------------------------------------------------------
//
// Function: TerminateExtension, public
//
// Synposis: Called by IIS during shutdown
// History: 29-Apr-96 KyleP Created
//
//----------------------------------------------------------------------------
BOOL WINAPI TerminateExtension( DWORD dwFlags )
{
EnterCriticalSection( &g_csInitExclusive );
TRANSLATE_EXCEPTIONS;
BOOL fOK = FALSE;
if ( dwFlags & HSE_TERM_MUST_UNLOAD )
{
TRY
{
Win4Assert( 0 != g_cClients );
g_cClients--;
if ( 0 == g_cClients )
{
ciGibDebugOut(( DEB_WARN, "Mandatory extension unload. Shutting down CI.\n" ));
TheWebQueryCache.Shutdown();
TheWebPendingRequestQueue.Shutdown();
//
// Wait for all ISAPI threads to exit before shutting down CI
//
while ( TheWebResourceArbiter.GetThreadCount() > 0 )
{
ciGibDebugOut(( DEB_WARN, "TerminateExtension: waiting for ISAPI threads to complete\n" ));
Sleep( 50 );
}
ciGibDebugOut(( DEB_WARN,
"TerminatExtension, request count %d\n",
TheWebQueryCache.ActiveRequestCount() ));
// note: don't call CIShutdown here. There's no need
// to, and it'll hose the impersonation token cache for
// webhits.
delete pTheGlobalIDQVariables;
pTheGlobalIDQVariables = 0;
}
}
CATCH( CException, e )
{
// ignore
}
END_CATCH
fOK = TRUE;
}
ciGibDebugOut(( DEB_WARN, "Extension unload: 0x%x. Flags = 0x%x\n",
fOK, dwFlags ));
UNTRANSLATE_EXCEPTIONS;
LeaveCriticalSection( &g_csInitExclusive );
return fOK;
} //TerminateExtension
//+---------------------------------------------------------------------------
//
// Function: CreateQueryFromRequest, private
//
// Synposis: Issues a query from a request.
//
// Arguments: [outputFormat] -- returns the formatting info.
// [localVars] -- returns the local variables.
// [wcsIDQFile] -- returns the idq file name.
// [webServer] -- web server for the request.
// [eErrorClass] -- returns the error class
// [status] -- returns the error code
// [fPending] -- returns TRUE if the request is pending
//
// History: 96-Apr-15 dlee created from existing code
//
//----------------------------------------------------------------------------
#if (CIDBG == 0)
inline
#endif
CWQueryItem * CreateQueryFromRequest( XPtr<COutputFormat> & outputFormat,
XPtr<CVariableSet> & localVars,
WCHAR * wcsIDQFile,
CWebServer & webServer,
int & eErrorClass,
NTSTATUS & status,
BOOL & fPending )
{
//
// NOTE: COutputFormat makes a **copy** of the web server. This
// copy should be used exclusively from this point on. The
// original web server will still be used by callers of this
// routine in cases where we fail to create the copy.
//
outputFormat.Set( new COutputFormat( webServer ) );
localVars.Set( new CVariableSet );
CSecurityIdentity securityIdentity;
XArray<WCHAR> xLocale;
//
// Update the original web server, in case we use it in a top-level
// error path.
//
webServer = outputFormat.GetReference();
LCID locale = GetBrowserLCID( outputFormat.GetReference() , xLocale );
outputFormat->LoadNumberFormatInfo( locale, GetBrowserCodepage(outputFormat.GetReference(), locale) );
localVars->AddExtensionControlBlock( outputFormat.GetReference() );
ULONG cwc = MAX_PATH;
BOOL fOK = outputFormat->GetCGI_PATH_TRANSLATED( wcsIDQFile, cwc );
if ( !fOK )
{
wcsIDQFile[0] = 0;
THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) );
}
outputFormat->SetCodePage(outputFormat->CodePage());
Win4Assert( fOK );
if ( IsNetPath(wcsIDQFile) )
{
ciGibDebugOut(( DEB_ERROR, "Path for idq file (%ws) is a UNC name\n",
wcsIDQFile ));
THROW( CIDQException(MSG_CI_SCRIPTS_ON_REMOTE_UNC, 0) );
}
CWQueryItem *pItem = 0;
//
// Check to see whether this is an .IDQ or .IDA file.
//
static WCHAR const wszAdmin[] = L".IDA";
static unsigned const ccAdmin = sizeof(wszAdmin)/sizeof(wszAdmin[0]) - 1;
if ( cwc > ccAdmin && 0 == _wcsicmp( wszAdmin, wcsIDQFile + cwc - ccAdmin - 1 ) )
{
CVirtualString IDAResults;
DoAdmin( wcsIDQFile,
localVars.GetReference(),
outputFormat.GetReference(),
IDAResults );
if ( outputFormat->WriteClient( IDAResults ) )
outputFormat->SetHttpStatus( HTTP_STATUS_OK );
else
{
eErrorClass = eWebServerWriteError;
outputFormat->SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
}
}
else
{
//
// Atempt to find an existing query using this IDQ file, &
// sequence number, based on the bookmark received.
//
fPending = FALSE;
pItem = TheWebQueryCache.CreateOrFindQuery( wcsIDQFile,
localVars,
outputFormat,
securityIdentity,
fPending );
if ( fPending )
{
Win4Assert( 0 == pItem );
}
else
{
TRY
{
Win4Assert( !pItem->IsCanonicalOutput() );
CVirtualString queryResults( 16384 );
//
// Write the query results to a WCHAR string buffer
// Initial virtual string size is in WCHARs
//
pItem->OutputQueryResults( localVars.GetReference(),
outputFormat.GetReference(),
queryResults );
//
// Send the query results to the browser
//
if ( outputFormat->WriteClient( queryResults ) )
outputFormat->SetHttpStatus( HTTP_STATUS_OK );
else
{
eErrorClass = eWebServerWriteError;
outputFormat->SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
}
}
CATCH( CException, e )
{
eErrorClass = eDefaultISAPIError;
status = e.GetErrorCode();
}
END_CATCH
}
}
return pItem;
} //CreateQueryFromRequest
//+---------------------------------------------------------------------------
//
// Function: ReportErrorNoThrow, public
//
// Synposis: Attempts to report an error condition and log the query
//
// Arguments: [localVars] -- local variables.
// [eErrorClass] -- error class
// [status] -- status code of faulure
// [ulErrorLine] -- line # of the error
// [wcsErrorFile] -- file associated with error
// [outputFormat] -- formatting info.
// [webServer] -- web server for the request.
//
// History: 96-Nov-25 dlee created from existing code, added TRY
//
//----------------------------------------------------------------------------
void ReportErrorNoThrow(
XPtr<CVariableSet> & localVars,
int eErrorClass,
NTSTATUS status,
ULONG ulErrorLine,
WCHAR const * wcsErrorFile,
XPtr<COutputFormat> & outputFormat,
CWebServer & webServer )
{
TRY
{
WCHAR * wcsRestriction = 0;
//
// Lookup the restriction, if one has been fully constructed.
//
if ( 0 != localVars.GetPointer() )
{
CVariable * pVarRestriction = localVars->Find(ISAPI_CI_RESTRICTION);
if ( 0 != pVarRestriction )
{
ULONG cwcValue;
wcsRestriction = pVarRestriction->GetStringValueRAW( outputFormat.GetReference(), cwcValue );
}
}
//
// Attempt to write out the error picture, if appropriate
//
CVirtualString vString;
GetErrorPageNoThrow( eErrorClass,
status,
ulErrorLine,
wcsErrorFile,
localVars.GetPointer(),
outputFormat.GetPointer(),
outputFormat.GetPointer() ? outputFormat->GetLCID() : 0,
webServer,
vString );
ciGibDebugOut(( DEB_IWARN, "WARNING: %ws\n", vString.Get() ));
webServer.WriteClient( vString );
Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST );
//
// Log the restriction in the failed query. It may not have
// been logged yet since we may have thrown before it was
// logged in the query execution path.
//
// if ( 0 != wcsRestriction )
// webServer.WriteLogData( wcsRestriction );
}
CATCH( CException, e )
{
// ignore -- not enough memory to output an error message
}
END_CATCH
} //ReportErrorNoThrow
//+---------------------------------------------------------------------------
//
// Function: ReportErrorNoThrow, public
//
// Synposis: Attempts to report an error condition and log the query
//
// Arguments: [localVars] -- local variables.
// [scError] -- error code
// [pwszErrorMessage] -- Description provided by Ole-DB error svc.
// [outputFormat] -- formatting info.
// [webServer] -- web server for the request.
//
// History: 97-May-08 KrishnaN created from existing ReportErrorNoThrow
//
//----------------------------------------------------------------------------
void ReportErrorNoThrow(
XPtr<CVariableSet> & localVars,
int eErrorClass,
SCODE scError,
WCHAR const * pwszErrorMessage,
XPtr<COutputFormat> & outputFormat,
CWebServer & webServer )
{
TRY
{
WCHAR * wcsRestriction = 0;
//
// Lookup the restriction, if one has been fully constructed.
//
if ( 0 != localVars.GetPointer() )
{
CVariable * pVarRestriction = localVars->Find(ISAPI_CI_RESTRICTION);
if ( 0 != pVarRestriction )
{
ULONG cwcValue;
wcsRestriction = pVarRestriction->GetStringValueRAW( outputFormat.GetReference(), cwcValue );
}
}
//
// Attempt to write out the error picture, if appropriate
//
CVirtualString vString;
GetErrorPageNoThrow(eErrorClass,
scError,
pwszErrorMessage,
localVars.GetPointer(),
outputFormat.GetPointer(),
outputFormat.GetPointer() ? outputFormat->GetLCID() : 0,
webServer,
vString );
ciGibDebugOut(( DEB_IWARN, "WARNING: %ws\n", vString.Get() ));
webServer.WriteClient( vString );
Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST );
//
// Log the restriction in the failed query. It may not have
// been logged yet since we may have thrown before it was
// logged in the query execution path.
//
// if ( 0 != wcsRestriction )
// webServer.WriteLogData( wcsRestriction );
}
CATCH( CException, e )
{
// ignore -- not enough memory to output an error message
}
END_CATCH
} //ReportErrorNoThrow
//+---------------------------------------------------------------------------
//
// Function: ProcessWebRequest, public
//
// Synposis: Issues a query from a request.
//
// Arguments: [webServer] -- web server for the request.
//
// Returns: The HSE_STATUS code.
//
// History: 96-Apr-15 dlee created from existing code
// 98-Sep-16 KLam Checks for valid method
//
//----------------------------------------------------------------------------
DWORD ProcessWebRequest(
CWebServer & webServer )
{
Win4Assert( HTTP_STATUS_ACCEPTED == webServer.GetHttpStatus() );
WCHAR wcsIDQFile[MAX_PATH];
wcsIDQFile[0] = 0;
CWQueryItem *pItem = 0;
XPtr<COutputFormat> outputFormat;
XPtr<CVariableSet> localVars;
NTSTATUS status = STATUS_SUCCESS; // Error code from query
ULONG ulErrorLine; // Line # in IDQ file error occured
int eErrorClass; // Type of error, IDQ, HTX, parse, ...
WCHAR const * wcsErrorFile = 0; // Name of file containing error
BOOL fPending = FALSE;
//
// Set the following flag to TRUE if we encounter an error
// whose description is already available.
//
BOOL fReportErrorWithDescription = FALSE;
BSTR bstrErrorDescription = 0;
//
// Make sure we have a valid method
//
if ( strcmp ( webServer.GetMethod(), "HEAD" ) == 0 )
{
//
// Do not need to execute the query if the client only wants the head
//
if ( webServer.WriteHeader() )
webServer.SetHttpStatus ( HTTP_STATUS_OK );
else
{
eErrorClass = eWebServerWriteError;
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
return HSE_STATUS_ERROR;
}
return HSE_STATUS_SUCCESS;
}
// Only support GET and POST for queries
else if ( strcmp( webServer.GetMethod(), "GET" ) != 0
&& strcmp ( webServer.GetMethod(), "POST" ) != 0 )
{
// HTTP 1.1 Spec determines value of header status string
if ( webServer.WriteHeader( NULL, "501 Not Implemented" ) )
webServer.SetHttpStatus ( HTTP_STATUS_NOT_SUPPORTED );
else
{
eErrorClass = eWebServerWriteError;
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
}
return HSE_STATUS_ERROR;
}
else
{
TRY
{
pItem = CreateQueryFromRequest( outputFormat,
localVars,
wcsIDQFile,
webServer,
eErrorClass,
status,
fPending );
}
CATCH( CPListException, e )
{
status = e.GetPListError();
ulErrorLine = e.GetLine();
eErrorClass = eIDQPlistError;
wcsErrorFile = wcsIDQFile;
Win4Assert( STATUS_SUCCESS != status );
}
AND_CATCH( CIDQException, e )
{
status = e.GetErrorCode();
ulErrorLine = e.GetErrorIndex();
eErrorClass = eIDQParseError;
wcsErrorFile = wcsIDQFile;
Win4Assert( STATUS_SUCCESS != status );
}
AND_CATCH( CHTXException, e )
{
status = e.GetErrorCode();
ulErrorLine = e.GetErrorIndex();
eErrorClass = eHTXParseError;
wcsErrorFile = e.GetHTXFileName();
//
// copy the error file name; it's stored on the stack below
// this function.
//
ULONG cchFileName = min( wcslen(wcsErrorFile) + 1, MAX_PATH );
Win4Assert(cchFileName < MAX_PATH);
RtlCopyMemory( wcsIDQFile,
wcsErrorFile,
sizeof(WCHAR) * cchFileName );
wcsIDQFile[MAX_PATH-1] = 0;
wcsErrorFile = wcsIDQFile;
Win4Assert( STATUS_SUCCESS != status );
}
AND_CATCH( CParserException, e )
{
status = e.GetParseError();
ulErrorLine = 0;
eErrorClass = eRestrictionParseError;
wcsErrorFile = wcsIDQFile;
Win4Assert( STATUS_SUCCESS != status );
}
AND_CATCH( CPostedOleDBException, e )
{
//
// When the execution error was detected, the Ole DB error
// info was retrieved and stored in the exception object.
// We retrieve that here and compose the error message.
//
status = e.GetErrorCode();
eErrorClass = e.GetErrorClass();
Win4Assert( STATUS_SUCCESS != status );
XInterface <IErrorInfo> xErrorInfo(e.AcquireErrorInfo());
if (xErrorInfo.GetPointer())
xErrorInfo->GetDescription(&bstrErrorDescription);
if (bstrErrorDescription)
fReportErrorWithDescription = TRUE;
else
{
// NO description. Follow the normal path.
ulErrorLine = 0;
wcsErrorFile = wcsIDQFile;
}
}
AND_CATCH( CException, e )
{
status = e.GetErrorCode();
ulErrorLine = 0;
eErrorClass = eDefaultISAPIError;
wcsErrorFile = wcsIDQFile;
Win4Assert( STATUS_SUCCESS != status );
}
END_CATCH
}
TRY
{
if ( STATUS_SUCCESS != status )
{
fPending = FALSE;
// the request failed, but we're returning an error message,
// so indicate that everything is ok.
webServer.SetHttpStatus( HTTP_STATUS_OK );
if (fReportErrorWithDescription)
{
Win4Assert(bstrErrorDescription);
ReportErrorNoThrow(localVars,
eErrorClass,
status,
(WCHAR const *)bstrErrorDescription,
outputFormat,
webServer );
SysFreeString(bstrErrorDescription);
}
else
{
Win4Assert(0 == bstrErrorDescription);
ReportErrorNoThrow( localVars,
eErrorClass,
status,
ulErrorLine,
wcsErrorFile,
outputFormat,
webServer );
}
if ( 0 != pItem )
pItem->Zombify();
}
TheWebQueryCache.Release( pItem );
}
CATCH( CException, e )
{
ciGibDebugOut(( DEB_ERROR, "ProcessWebRequest Error 0x%X\n", e.GetErrorCode() ));
Win4Assert( e.GetErrorCode() != STATUS_ACCESS_VIOLATION );
}
END_CATCH
#if CIDBG == 1
//
// If fPending is TRUE, the http status of the ecb can't be trusted,
// because the request may have asynchronously completed by now:
//
if ( !fPending )
{
DWORD dwHttpStatus = webServer.GetHttpStatus();
Win4Assert( HTTP_STATUS_ACCEPTED != dwHttpStatus );
Win4Assert( HTTP_STATUS_OK == dwHttpStatus ||
HTTP_STATUS_SERVER_ERROR == dwHttpStatus ||
HTTP_STATUS_DENIED == dwHttpStatus ||
HTTP_STATUS_SERVICE_UNAVAIL == dwHttpStatus );
}
#endif // CIDBG == 1
if ( fPending )
return HSE_STATUS_PENDING;
return HSE_STATUS_SUCCESS;
} //ProcessWebRequest
//+---------------------------------------------------------------------------
//
// Function: HttpExtensionProc, public
//
// Synposis: Handles a request from the web server
//
// Arguments: [pEcb] -- block from the server
//
// History: 96-Apr-15 dlee created header
//
//----------------------------------------------------------------------------
DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pEcb )
{
if ( 0 == pTheGlobalIDQVariables || fTheActiveXSearchShutdown )
{
ciGibDebugOut(( DEB_GIB_REQUEST,
"Indexing Service being shutdown\n" ));
pEcb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
return HSE_STATUS_ERROR;
}
CIncomingThread incoming( TheWebResourceArbiter );
TheWebQueryCache.IncrementActiveRequests();
CWebServer webServer( pEcb );
DWORD hseStatus = HSE_STATUS_ERROR;
webServer.SetHttpStatus( HTTP_STATUS_ACCEPTED );
TRANSLATE_EXCEPTIONS;
TRY
{
if ( TheWebResourceArbiter.IsSystemBusy() )
{
if ( TheWebQueryCache.AddToPendingRequestQueue( pEcb ) )
{
ciGibDebugOut(( DEB_GIB_REQUEST, "Server busy, queueing request\n" ));
hseStatus = HSE_STATUS_PENDING;
TheWebQueryCache.Wakeup();
TheWebQueryCache.UpdatePendingRequestCount();
}
else
{
TheWebQueryCache.IncrementRejectedRequests();
ciGibDebugOut(( DEB_GIB_REQUEST,
"Server too busy, failing request!!!\n" ));
ReturnServerError( HTTP_STATUS_SERVICE_UNAVAIL, webServer );
hseStatus = HSE_STATUS_SUCCESS;
}
}
else
{
ciGibDebugOut(( DEB_GIB_REQUEST, "Server not busy, processing request\n" ));
hseStatus = ProcessWebRequest( webServer );
}
}
CATCH( CException, e )
{
hseStatus = HSE_STATUS_ERROR;
}
END_CATCH
UNTRANSLATE_EXCEPTIONS;
if ( HSE_STATUS_PENDING != hseStatus )
{
TheWebQueryCache.DecrementActiveRequests();
ciGibDebugOut(( DEB_GIB_REQUEST,
"Falling out of isapi proc, active: %d\n",
TheWebQueryCache.ActiveRequestCount() ));
Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST &&
webServer.GetHttpStatus() <= HTTP_STATUS_LAST );
if ( ( webServer.GetHttpStatus() < HTTP_STATUS_FIRST ) ||
( webServer.GetHttpStatus() > HTTP_STATUS_LAST ) )
{
ciGibDebugOut(( DEB_WARN,
"non-pending hse %d ECB %08x status invalid: %d\n",
hseStatus,
pEcb,
webServer.GetHttpStatus() ));
webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
}
}
else
{
//
// The pending request may have asynchronously completed by now,
// so nothing can be asserted about the http status except that it
// is a valid http status code, which retrieving the status does.
//
#if CIDBG == 1
webServer.GetHttpStatus();
#endif
}
ciGibDebugOut(( DEB_ITRACE, "httpExtensionProc: hse %d, http %d\n",
hseStatus, webServer.GetHttpStatus() ));
return hseStatus;
} //HttpExtensionProc
//+---------------------------------------------------------------------------
//
// Method: CWebPendingQueue::CWebPendingQueue, public
//
// Synposis: Constructs the pending request queue
//
// History: 96-Apr-15 dlee created
//
//----------------------------------------------------------------------------
CWebPendingQueue::CWebPendingQueue()
: TFifoCircularQueue<CWebPendingItem>
( TheIDQRegParams.GetISRequestQueueSize() ),
_ulSignature( LONGSIG( 'p', 'e', 'n', 'd' ) )
{
} //CWebPendingQueue
//+---------------------------------------------------------------------------
//
// Method: CWebResourceArbiter::CWebResourceArbiter, public
//
// Synposis: Constructs the web resource arbiter
//
// History: 96-Apr-15 dlee created
//
//----------------------------------------------------------------------------
CWebResourceArbiter::CWebResourceArbiter() :
_ulSignature( LONGSIG( 'a', 'r', 'b', 'i' ) ),
_cThreads( 0 )
{
ULONG factor = TheIDQRegParams.GetISRequestThresholdFactor();
Win4Assert( 0 != factor );
SYSTEM_INFO si;
GetSystemInfo( &si );
_maxThreads = si.dwNumberOfProcessors * factor;
Win4Assert( _maxThreads >= (LONG) factor );
_maxPendingQueries = TheIDQRegParams.GetMaxActiveQueryThreads() *
factor;
} //CWebResourceArbiter
//+---------------------------------------------------------------------------
//
// Method: CWebResourceArbiter::IsSystemBusy, public
//
// Synposis: Determines if the system is too busy to process a request.
//
// Returns: TRUE if the request should be queued or rejected, FALSE
// if the system is free enough to handle it.
//
// History: 96-Apr-15 dlee created
//
//----------------------------------------------------------------------------
BOOL CWebResourceArbiter::IsSystemBusy()
{
return ( _cThreads > _maxThreads ) ||
( TheWebQueryCache.PendingQueryCount() >= _maxPendingQueries );
} //IsSystemBusy
//+---------------------------------------------------------------------------
//
// Function: DllMain
//
// Synopsis: Called from C-Runtime on process/thread attach/detach
//
// Arguments: [hInstance] -- Module handle
// [dwReason] -- Reason for being called
// [lpReserved] --
//
// History: 23-Apr-97 dlee Created
//
//----------------------------------------------------------------------------
#if CIDBG == 1
#define VER_CIDEBUG "chk"
#else // CIDBG == 1
#define VER_CIDEBUG "fre"
#endif // CIDBG == 1
#if IDQ_VERSION == 3
#define VER_PROJECT "query"
#else // IDQ_VERSION != 3
#define VER_PROJECT "indexsrv"
#endif // IDQ_VERSION == 3
#define MAKELITERALSTRING( s, lit ) s #lit
#define MAKELITERAL( s, lit ) MAKELITERALSTRING( s, lit )
#define VERSION_STRING MAKELITERAL("Indexing Service ", IDQ_VERSION) \
"(" VER_PROJECT ") " VER_CIDEBUG \
MAKELITERAL(" built by ", BUILD_USERNAME) \
MAKELITERAL(" with ", VER_PRODUCTBUILD) \
" on " __DATE__ " at " __TIME__
char g_ciBuild[ ] = VERSION_STRING;
BOOL WINAPI DllMain(
HANDLE hInstance,
DWORD dwReason,
void * lpReserved )
{
BOOL fRetval = TRUE;
TRANSLATE_EXCEPTIONS;
TRY
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls( (HINSTANCE) hInstance );
InitializeCriticalSection( &g_csInitExclusive );
break;
}
case DLL_PROCESS_DETACH:
{
DeleteCriticalSection( &g_csInitExclusive );
break;
}
}
}
CATCH( CException, e )
{
// About the only thing this could be is STATUS_NO_MEMORY which
// can be thrown by InitializeCriticalSection.
ciGibDebugOut(( DEB_ERROR,
"IDQ: Exception %#x in DllMain\n",
e.GetErrorCode()));
#if CIDBG == 1 // for debugging NTRAID 340297
if (e.GetErrorCode() == STATUS_NO_MEMORY)
DbgPrint( "IDQ: STATUS_NO_MEMORY exception in DllMain\n");
else
DbgPrint( "IDQ: ??? Exception in DllMain\n");
#endif // CIDBG == 1
fRetval = FALSE;
}
END_CATCH
UNTRANSLATE_EXCEPTIONS;
return fRetval;
} //DllMain