695 lines
15 KiB
C
695 lines
15 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
setuplog.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Routines for logging actions and errors during setup.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Steve Owen (SteveOw) 1-Sep-1996
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <nturtl.h>
|
|||
|
#include <windows.h>
|
|||
|
#include "setuplog.h"
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
VOID
|
|||
|
SetupLogAssertFail(
|
|||
|
IN PSTR FileName,
|
|||
|
IN UINT LineNumber,
|
|||
|
IN PSTR Condition
|
|||
|
)
|
|||
|
{
|
|||
|
CHAR Msg[4096];
|
|||
|
|
|||
|
wsprintfA(
|
|||
|
Msg,
|
|||
|
"SetupLog: Assertion failure at line %u in file %s: %s\r\n",
|
|||
|
LineNumber,
|
|||
|
FileName,
|
|||
|
Condition
|
|||
|
);
|
|||
|
|
|||
|
OutputDebugStringA(Msg);
|
|||
|
DebugBreak();
|
|||
|
}
|
|||
|
|
|||
|
#define MYASSERT(x) if(!(x)) { SetupLogAssertFail(__FILE__,__LINE__,#x); }
|
|||
|
|
|||
|
#else
|
|||
|
#define MYASSERT(x)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Pointer to structure given to us during initialization that provides all
|
|||
|
// the callbacks and global info we need.
|
|||
|
//
|
|||
|
PSETUPLOG_CONTEXT Context = NULL;
|
|||
|
|
|||
|
BOOL
|
|||
|
pLogAction (
|
|||
|
IN LPCTSTR Message
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Writes an entry into the Setup Action Log. This routine is responsible
|
|||
|
for setting the format of the log file entries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Buffer that contains the text to write.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean indicating whether the operation was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return Context->Write (Context->hActionLog, Message);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
pLogError (
|
|||
|
IN LogSeverity Severity,
|
|||
|
IN LPCTSTR Message
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Writes an entry into the Setup Error Log. This routine is responsible
|
|||
|
for setting the format of the log file entries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Buffer that contains the text to write.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean indicating whether the operation was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL b;
|
|||
|
|
|||
|
Context->Lock(Context->Mutex);
|
|||
|
|
|||
|
//
|
|||
|
// Write the severity description.
|
|||
|
//
|
|||
|
if(Context->SeverityDescriptions[Severity]) {
|
|||
|
b = Context->Write (Context->hErrorLog,
|
|||
|
Context->SeverityDescriptions[Severity]);
|
|||
|
b = b && Context->Write (Context->hErrorLog, TEXT(":\r\n"));
|
|||
|
} else {
|
|||
|
b = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Write the text.
|
|||
|
//
|
|||
|
b = b && Context->Write (Context->hErrorLog, Message);
|
|||
|
|
|||
|
//
|
|||
|
// Write a terminating marker.
|
|||
|
//
|
|||
|
b = b && Context->Write (Context->hErrorLog, SETUPLOG_ITEM_TERMINATOR);
|
|||
|
|
|||
|
Context->Unlock(Context->Mutex);
|
|||
|
|
|||
|
return(b);
|
|||
|
}
|
|||
|
|
|||
|
PTSTR
|
|||
|
pFormatMessage (
|
|||
|
IN PSETUPLOG_CONTEXT MyContext,
|
|||
|
IN LPCTSTR MessageString,
|
|||
|
IN UINT MessageId,
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrapper for Context->Format callback routine. This routine passes its
|
|||
|
variable argument list to Context->Format as a va_list.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MyContext - provides callback routines.
|
|||
|
|
|||
|
MessageId - supplies message-table identifier or win32 error code
|
|||
|
for the message.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to a buffer containing the formatted string.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
PTSTR p;
|
|||
|
|
|||
|
va_start(arglist, MessageId);
|
|||
|
p = MyContext->Format (MessageString,MessageId,&arglist);
|
|||
|
va_end(arglist);
|
|||
|
return(p);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SetuplogInitializeEx(
|
|||
|
IN PSETUPLOG_CONTEXT SetuplogContext,
|
|||
|
IN BOOL WipeLogFile,
|
|||
|
IN LPCTSTR ActionFilename,
|
|||
|
IN LPCTSTR ErrorFilename,
|
|||
|
IN PVOID Reserved1,
|
|||
|
IN DWORD Reserved2
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens the Setup log files.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SetuplogContext - pointer to a context that has been filled in with the
|
|||
|
required callback routines by the caller.
|
|||
|
|
|||
|
WipeLogFile - Boolean indicating whether any existing log files should be
|
|||
|
deleted (TRUE) or whether we should append onto existing files (FALSE).
|
|||
|
|
|||
|
ActionFilename - filename to be used for the Action Log.
|
|||
|
|
|||
|
ErrorFilename - filename to be used for the Error Log.
|
|||
|
|
|||
|
Reserved1 - Reserved for future use--must be NULL.
|
|||
|
|
|||
|
Reserved2 - Reserved for future use--must be 0.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean indicating whether the operation was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if(Reserved1 || Reserved2) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Context = SetuplogContext;
|
|||
|
Context->WorstError = LogSevInformation;
|
|||
|
|
|||
|
Context->hActionLog = Context->OpenFile(
|
|||
|
ActionFilename, WipeLogFile);
|
|||
|
|
|||
|
Context->hErrorLog = Context->OpenFile(
|
|||
|
ErrorFilename, WipeLogFile);
|
|||
|
|
|||
|
return (Context->hActionLog != INVALID_HANDLE_VALUE &&
|
|||
|
Context->hErrorLog != INVALID_HANDLE_VALUE);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SetuplogInitialize(
|
|||
|
IN PSETUPLOG_CONTEXT SetuplogContext,
|
|||
|
IN BOOL WipeLogFile
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens the Setup log files with default file names.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SetuplogContext - pointer to a context that has been filled in with the
|
|||
|
required callback routines by the caller.
|
|||
|
|
|||
|
WipeLogFile - Boolean indicating whether any existing log files should be
|
|||
|
deleted (TRUE) or whether we should append onto existing files (FALSE).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean indicating whether the operation was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return SetuplogInitializeEx(
|
|||
|
SetuplogContext,
|
|||
|
WipeLogFile,
|
|||
|
SETUPLOG_ACTION_FILENAME,
|
|||
|
SETUPLOG_ERROR_FILENAME,
|
|||
|
NULL,
|
|||
|
0
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
PTSTR
|
|||
|
SetuplogFormatMessageWithContextV(
|
|||
|
IN PSETUPLOG_CONTEXT MyContext,
|
|||
|
IN DWORD Flags,
|
|||
|
IN LPCTSTR MessageString,
|
|||
|
IN UINT MessageId,
|
|||
|
IN va_list *ArgumentList
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Formats a specified message with caller-supplied arguments. The message
|
|||
|
can contain any number of imbedded messages.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MyContext - provides callback routines. This parameter is provided so that
|
|||
|
messages can be formatted even the global Context has not been
|
|||
|
initialized because we're not in Setup. This ability is needed by the
|
|||
|
Add/Remove Programs applet. The only fields that we use in this
|
|||
|
structure are AllocMem, FreeMem, and Format.
|
|||
|
|
|||
|
Flags - Optional flags that can modify how the formatting is performed.
|
|||
|
|
|||
|
MessageString - pointer to a buffer containing unformatted message text.
|
|||
|
If this value is SETUPLOG_USE_MESSAGEID, then MessageId is used to
|
|||
|
generate the message text. Otherwise, MessageId is unused.
|
|||
|
|
|||
|
MessageID - ID of the outer level message to be formatted
|
|||
|
|
|||
|
ArgumentList - list of strings to be substituted into the message. The
|
|||
|
order of items in the ArgumentList is given by:
|
|||
|
ArgumentList = Arg1,...,ArgN,NULL,{ImbeddedMessage},NULL
|
|||
|
ImbeddedMessage = MessageID,Arg1,...,ArgN,NULL,{ImbeddedMessage}
|
|||
|
where Arg1,...,ArgN are the arguments for MessageID
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to a buffer containing the formatted string. If an error prevented
|
|||
|
the routine from completing successfully, NULL is returned. The caller
|
|||
|
can free the buffer with Context->MyFree().
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list major_ap, minor_ap;
|
|||
|
UINT NumberOfArguments, i;
|
|||
|
UINT MinorMessageId;
|
|||
|
PVOID p, *MajorArgList;
|
|||
|
PTSTR MajorMessage, MinorMessage, MinorMessageString;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Handle a single message first.
|
|||
|
//
|
|||
|
if(Flags & SETUPLOG_SINGLE_MESSAGE) {
|
|||
|
return MyContext->Format (MessageString, MessageId, ArgumentList);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Count the number of arguments that go with the major message (MessageID)
|
|||
|
// and get ready to process the minor (imbedded) message if there is one
|
|||
|
//
|
|||
|
minor_ap = *ArgumentList;
|
|||
|
NumberOfArguments = 0;
|
|||
|
major_ap = minor_ap;
|
|||
|
while (p=va_arg(minor_ap, PVOID)) {
|
|||
|
NumberOfArguments++;
|
|||
|
}
|
|||
|
MYASSERT (NumberOfArguments < 7);
|
|||
|
|
|||
|
MinorMessageString = va_arg(minor_ap, PTSTR);
|
|||
|
if (MinorMessageString) {
|
|||
|
|
|||
|
//
|
|||
|
// We've got a minor message, so process it first
|
|||
|
//
|
|||
|
MinorMessageId = va_arg(minor_ap, UINT);
|
|||
|
MinorMessage = SetuplogFormatMessageWithContextV (
|
|||
|
MyContext,
|
|||
|
Flags,
|
|||
|
MinorMessageString,
|
|||
|
MinorMessageId,
|
|||
|
&minor_ap);
|
|||
|
|
|||
|
if (!MinorMessage) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now we handle the major message
|
|||
|
// Ugly hack: since we don't know how to bulid a va_list, we've
|
|||
|
// got to let the compiler do it.
|
|||
|
//
|
|||
|
MajorArgList = MyContext->AllocMem ((NumberOfArguments) * sizeof(PVOID));
|
|||
|
if (!MajorArgList) {
|
|||
|
MyContext->FreeMem (MinorMessage);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
for (i=0; i<NumberOfArguments; i++) {
|
|||
|
MajorArgList[i] = va_arg (major_ap, PVOID);
|
|||
|
}
|
|||
|
switch (NumberOfArguments) {
|
|||
|
case 0:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
case 1:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MajorArgList[0],
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MajorArgList[0],
|
|||
|
MajorArgList[1],
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
case 3:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MajorArgList[0],
|
|||
|
MajorArgList[1],
|
|||
|
MajorArgList[2],
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MajorArgList[0],
|
|||
|
MajorArgList[1],
|
|||
|
MajorArgList[2],
|
|||
|
MajorArgList[3],
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
case 5:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MajorArgList[0],
|
|||
|
MajorArgList[1],
|
|||
|
MajorArgList[2],
|
|||
|
MajorArgList[3],
|
|||
|
MajorArgList[4],
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
case 6:
|
|||
|
MajorMessage = pFormatMessage (
|
|||
|
MyContext,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
MajorArgList[0],
|
|||
|
MajorArgList[1],
|
|||
|
MajorArgList[2],
|
|||
|
MajorArgList[3],
|
|||
|
MajorArgList[4],
|
|||
|
MajorArgList[5],
|
|||
|
MinorMessage);
|
|||
|
break;
|
|||
|
default:
|
|||
|
MajorMessage = NULL;
|
|||
|
MYASSERT (0);
|
|||
|
}
|
|||
|
MyContext->FreeMem (MajorArgList);
|
|||
|
MyContext->FreeMem (MinorMessage);
|
|||
|
} else {
|
|||
|
MajorMessage = MyContext->Format (MessageString, MessageId, &major_ap);
|
|||
|
}
|
|||
|
|
|||
|
return MajorMessage;
|
|||
|
}
|
|||
|
|
|||
|
PTSTR
|
|||
|
SetuplogFormatMessageV(
|
|||
|
IN DWORD Flags,
|
|||
|
IN LPCTSTR MessageString,
|
|||
|
IN UINT MessageId,
|
|||
|
IN va_list *ArgumentList
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrapper for SetuplogFormatMessageWithContextV.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
See FormatMessageWithContextV.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
See FormatMessageWithContextV.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Make sure we've been initialized
|
|||
|
//
|
|||
|
if(!Context) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
return SetuplogFormatMessageWithContextV(
|
|||
|
Context,
|
|||
|
Flags,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
ArgumentList
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
PTSTR
|
|||
|
SetuplogFormatMessage(
|
|||
|
IN DWORD Flags,
|
|||
|
IN LPCTSTR MessageString,
|
|||
|
IN UINT MessageId,
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrapper for SetuplogFormatMessageWithContextV. This routine passes its
|
|||
|
variable argument list to SetuplogFormatMessageV as a va_list.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
See FormatMessageWithContextV.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
See FormatMessageWithContextV.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
PTSTR p;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure we've been initialized
|
|||
|
//
|
|||
|
if(!Context) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
va_start(arglist,MessageId);
|
|||
|
p = SetuplogFormatMessageWithContextV(
|
|||
|
Context,
|
|||
|
Flags,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
&arglist);
|
|||
|
va_end(arglist);
|
|||
|
|
|||
|
return(p);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SetuplogErrorV(
|
|||
|
IN LogSeverity Severity,
|
|||
|
IN LPCTSTR MessageString,
|
|||
|
IN UINT MessageId, OPTIONAL
|
|||
|
IN va_list *ArgumentList
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Writes an entry to the Setup Error Log.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Severity - Severity of the error. The low word contains the actual number
|
|||
|
of the severity. The high word contains any flags that affect how the
|
|||
|
message is formatted.
|
|||
|
|
|||
|
MessageString - pointer to a buffer containing unformatted message text.
|
|||
|
If this value is SETUPLOG_USE_MESSAGEID, then MessageId is used to
|
|||
|
generate the message text. Otherwise, MessageId is unused.
|
|||
|
|
|||
|
MessageId - supplies message-table identifier or win32 error code
|
|||
|
for the message.
|
|||
|
|
|||
|
ArgumentList - supplies arguments to be inserted in the message text.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean indicating whether the operation was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL Status = FALSE;
|
|||
|
LPCTSTR Message;
|
|||
|
|
|||
|
if(Context) {
|
|||
|
|
|||
|
if(Message = SetuplogFormatMessageV (
|
|||
|
Severity,
|
|||
|
MessageString,
|
|||
|
MessageId,
|
|||
|
ArgumentList)) {
|
|||
|
|
|||
|
//
|
|||
|
// Now validate the Severity. Note that we don't have to do this
|
|||
|
// for SetuplogFormatMessageV, since it just looks at the flags
|
|||
|
// set in the high word.
|
|||
|
//
|
|||
|
Severity = LOWORD(Severity);
|
|||
|
if(Severity < LogSevMaximum) {
|
|||
|
Status = TRUE;
|
|||
|
} else {
|
|||
|
MYASSERT (Severity < LogSevMaximum);
|
|||
|
Severity = LogSevInformation;
|
|||
|
Status = FALSE;
|
|||
|
}
|
|||
|
Context->WorstError = max (Context->WorstError, Severity);
|
|||
|
|
|||
|
//
|
|||
|
// Write the message(s).
|
|||
|
//
|
|||
|
Status = pLogAction (Message) && Status;
|
|||
|
if(Severity != LogSevInformation) {
|
|||
|
Status = pLogError (Severity, Message) && Status;
|
|||
|
}
|
|||
|
Context->FreeMem (Message);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
if(!Status) {
|
|||
|
OutputDebugStringA("SETUPLOG: Unable to log a message.\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SetuplogError(
|
|||
|
IN LogSeverity Severity,
|
|||
|
IN LPCTSTR MessageString,
|
|||
|
IN UINT MessageId, OPTIONAL
|
|||
|
...
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Wrapper for SetuplogErrorV
|
|||
|
Make sure to pass two NULLs to end the arglist.
|
|||
|
Otherwise SetuplogFormatMessageWithContextV will cause an exception.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list arglist;
|
|||
|
BOOL Status;
|
|||
|
|
|||
|
va_start(arglist, MessageId);
|
|||
|
Status = SetuplogErrorV (Severity, MessageString, MessageId, &arglist);
|
|||
|
va_end(arglist);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
SetuplogTerminate(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Closes the Setup log files.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Boolean indicating whether the operation was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL Status = FALSE;
|
|||
|
|
|||
|
if(Context) {
|
|||
|
Context->CloseFile(Context->hActionLog);
|
|||
|
Context->CloseFile(Context->hErrorLog);
|
|||
|
|
|||
|
Context = NULL;
|
|||
|
Status = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|