3D PLM Enterprise Architecture |
Middleware Abstraction |
Using an Error Class with HRESULTs or ExceptionsAssociating information with errors |
Technical Article |
AbstractThis article explains how to use error classes and messages, and how to create new ones.
|
When you design and code your methods, and when the process goes out of the scope you have determined without being able to recover, you either return to the caller a HRESULT value stating that an error occurs or throw an exception. You associate with this HRESULT or make up the exception with an error class instance to convey the error severity, the error message, possibly filled with parameters you get from your method's variable values to show why the method goes out of its scope, and if the error class has data members, you can pass these variable values using these data members to the caller or exception catcher.
Dealing with error classes includes mainly:
[Top]
When you want to convey information with a returned HRESULT or throw an exception, you need to instantiate an existing error class
Choose an existing error class that matches the error. Avoid to create new error classes. In the same way, choose an existing error message that matches the error. Avoid to create new ones.
When you want to convey information with a returned HRESULT or throw an exception, you need to instantiate an existing error class, as follows:
... CATResourceError * pError = new CATResourceError("FileERR_2000", "CATFileErrorCatalog"); ... |
The first parameter is the error message key, without the possible suffix used as a descriptor, and the second parameter is the error message catalog file name, without extension. The file is named in this case CATFileErrorCatalog.CATNls and should be found in the directory concatenation set by the CATMsgCatalogPath environment variable at run time.
An error class that is not created using the macros may have additional constructor arguments, and may have initialization methods to call. If the error class you use has data members, they are intended to pass parameter values to the caller or exception catcher. Use run time values of appropriate variables of your method to value these parameters.
[Top]
If the error message includes parameters to value at run time, you should supply these values. To do this, convert the appropriate variables of your methods as CATUnicodeString instances, and assign them to the error class instance just created to build the message with these values.
...
char * pFileName = "CATError.CATNls";
CATUnicodeString Param1(pFileName);
CATString FolderName("msgcatalog");
char * pFolderName = FolderName.CastToCharPtr(); // First cast the CATString instance into a char *
CATUnicodeString Param2(pFolderName);
pError->
|
The parameter names, such as Param1
has no importance. They
should just be converted to CATUnicodeString instances and passed to
the error class using the appropriate method, here the SetNLSParams
method. The first parameter is the count of parameters to pass, and these
parameters should then be passed in the same order than in the message file.
In this case, the variable pFileName
is supposed to be a
pointer to char, thus allowing the use of a CATUnicodeString
constructor. The second one is a CATString instance, and must first
be converted into a pointer to char using the CastToCharPtr
method before being passed to the CATUnicodeString constructor.
BuildFromNum
method, as
follows:
...
int i = 10;
double x = 2.45;
CATUnicodeString Param1, Param2;
Param1.BuildFromNum(i);
Param2.BuildFromNum(x);
pError->
|
The parameter to convert into a CATUnicodeString class instance
with BuildFromNum
can be an int, a long, an unsigned long, a
double, or a long double.
If the message to use is a single one, use the SetNLSParameters
method. If you have a composite message, set the parameters, if any, for each
message of your composite message separately using the SetNLSRequestParams
,
SetNLSDiagnosticParams
, and SetNLSAdviceParams
methods
respectively. Refer to Creating New Error Messages to know
more about error messages.
[Top]
The error type and identifier are associated with the error to help the caller understand what happens and how to handle the error.
[Top]
The type of the error describes its severity. An error can have the following
types, whose values are taken from the CATErrorType
enumeration,
and the associated prompts are as follows:
CATErrorTypeCritical : a real problem occurs, and the method
cannot complete. It returns when the problem occurs. This is the default
if you don't set the error type. The associated prompt box must be an
instance of the CATDlgNotify class with the CATDlgNfyError
style. |
|
CATErrorTypeFatal : the method stops with no possible
recovery. The associated prompt box must be an instance of the CATDlgNotify
class with the CATDlgNfyAbortRetryIgnore style. |
|
CATErrorTypeWarning : something happens that doesn't stop
the method which completes, but returns a warning. The associated prompt
box must be an instance of the CATDlgNotify class with the CATDlgNfyWarning
style. |
|
CATErrorTypeInformation : there is no error and the method
successfully completes, but this information can be handy. The associated
prompt box must be an instance of the CATDlgNotify class with
the CATDlgNfyInformation style. |
The type is set using the SetType
method. It takes the error
type as parameter:
... pError->SetType(CATErrorTypeFatal); ... |
[Top]
The error identifier is part of the message key and deduced from it when passed to the constructor. Refer to Creating New Error Messages to know which part of the message key is used as error identifier.
[Top]
You can send the error message to the end user in a prompt box using a CATDlgNotify class instance, as follows.
... CATDlgNotify * pPromptBox = new CATDlgNotify(pParent, "Error", CATDlgNfyAbortRetryIgnore); pPromptBox->SetTitle(pOccurringError->GetNLSSource()); pPromptBox->SetText(pOccurringError->GetNLSMessage()); pPromptBox->SetVisibility(CATDlgShow); ... |
User the following styles according to the error type [2]:
Error Type |
Style |
CATErrorTypeCritical |
CATDlgNfyError |
CATErrorTypeFatal |
CATDlgNfyAbortRetryIgnore |
CATErrorTypeWarning |
CATDlgNfyWarning |
CATErrorTypeInformation |
CATDlgNfyInformation |
You should simply set the title using the GetNSLSource
method,
and the text using the GetNSLMessage
method.
[Top]
If the error is a major one, you must trace it. Error traceability is possible using two macros:
CATSysLogAbend
that logs a message passed as parameter, the
source where it is called, and the line in the source in the abend log, and:The code where the trace is located must not contain any test or branch instruction:
if (NULL == pPointer) { ... // Cleaning CATSysLogAbend("This pointer should never be NULL"); return CATReturnFailure; } |
CATSysLogError
that logs a message like CATSysLogAbend
in the potential abend log, but doesn't abend, either in a customer or
development environment. Its typical use is to test an argument:
if (NULL == pInputPointer) { ... // Cleaning CATSysLogError("Invalid NULL input pointer"); return CATReturnFailure; } |
The messages are passed as character strings to be logged in the abend log. They must be written in correct english since they can be read by the customer.
[Top]
You can can analyze the error class instance using the following methods:
Data to Analyze | Method | Comment |
---|---|---|
Error class base class name | IsAKindOf |
The error class base class name helps you determine which kind of error happens |
Error class name | ClassName |
The error class name helps you call the class methods or retrieve data members, if any |
Return code | GetReturnCode |
The return code helps you determine the code returned |
Error severity | GetInformationOnErrorType |
The error severity helps you decide if the error is critical, fatal, a warning, or an information |
Error context | GetSourceContext |
The source context is the name of the application that issues the error (CATIA by default) |
Error source | GetNLSSource |
The error source is made up of a concatenation of the source context, the error message catalog file name, and the error message key |
Error identifier | GetId |
The error identifier helps you precisely identify the error |
Error message key | GetMsgId |
The error message key helps you determine the message associated with the error |
Error message catalog | GetMsgCatalog |
The error message catalog helps you determine where the error message is stored |
Error message | GetNLSMessage |
The error message is retrieved as built by the caller with parameters valued |
Request part of the message | GetNLSRequest |
As above, for the Request part of the error message |
Diagnostic part of the message | GetNLSDiagnostic |
As above, for the Diagnostic part of the error message |
Advice part of the message | GetNLSAdvice |
As above, for the Advice part of the error message |
Source file name | GetSourceFileName |
The source file name is the path name of the source file in which the error occurs |
Source line number | GetSourceLineNumber |
The source line number is the number of the line in the source filewhere the error occurs |
If the error is a major one, you must trace the error, as described in Tracing the Error.
[Top]
The message associated with the error is stored in a message catalog file. This allows for message translation or customization. The message catalog file should be created as a text file in the CNext\resources\msgcatalog directory for the english version, and in:
and should be suffixed using CATNls. This file is put in the run time view thanks to the mkCreateRuntimeView command, and found using the CATMsgCatalogPath environment variable set by the mkrun command.
Assume that the following message is extracted from the CAAFileErrorCatalog.CATNls file.
An error message is associated with a key that must be unique in the message file and used in the code to fetch the message. It is generally a composite message, made of three elementary messages, as follows:
... FileERR_1999.Request = "Attempt to open the file /p"; FileERR_1999.Diagnostic = "This file is not found"; FileERR_1999.Advice = "Locate this file or try another one"; ... |
Messages have the following structure.
The key must be unique in a message catalog file, and is built using a prefix
of your own, here File
, followed by the error identifier, here ERR_1999
.
The descriptor is separated from the key by a dot, like a suffix, such as Diagnostic
.
The prefix and the descriptor are not required, but the error identifier must
always be ERR_nnnn
, where ERR
is required and nnnn
must be an integer. The error identifier must also be unique for a given message
catalog file.
Even if you think to write three different messages with the three
descriptors given above, they are handled as a single message using the message
key. Nevertheless, you need to set their parameters using the SetNLSRequestParams
,
SetNLSDiagnosticParams
, and SetNLSAdviceParams
methods
respectively.You can also create a message without descriptors, such as the
following:
... FileERR_2000 = "File /p not found.\nTry another one."; ... |
When you write your error messages, classify the information to pass to the end user using the descriptor:
As any message, an error message can contain parameters. The value of these
parameters are set at run time. To include parameters in your message, use the /p
keyword. You can also use /P
, or /p1
, /p2
,
or also /P1
, /P2
, and so on. Each time such a keyword
is found in the message, it is candidate to be filled in by a run time value. If
no value is passed for a given parameter, it is replaced by ?? in the displayed
message. The following is an example of an error message with parameters.
SketchLimitERR_0010.Request = "The selected elements /p1 and /p2 cannot be relimited"; SketchLimitERR_0010.Diagnostic = "Lengthed elements cannot be relimited.\nTheir lengthes are: \t/P1 for first element /p2 \t/P3 for second element /p4 They are converted into distances."; SketchLimitERR_0010.Advice = "To relimit, do not select lengthed elements"; |
Note that you can use special characters, such as \n or \t. This message is displayed at run time in a prompt as follows:
The title of the prompt box is made of the error source, that is, the concatenation of the running context, the error message catalog file, and the error message key. The running context, here CNext, is the name of the application from which the error is issued. The messages are displayed in the Request-Diagnostic-Advice order. The icon shown in the prompt box depends on the error type set at run time.
[Top]
An error class can be used for several errors dealing with a common topic. The error class you can create and instantiate should derive from one of the five following classes, since you should never derive from CATError directly:
These classes provide a first error classification:
You can refine this classification. For example, the CATFileError class could be dedicated to file errors and derive from CATResourceError. It is created using macros and have the following header file.
#include "CATResourceError.h" class CATFileError : public CATResourceError { public: CATDeclareError(CATFileError, CATResourceError) }; |
and the following source file:
#include "CATFileError.h" CATImplementError(CATFileError, CATResourceError); CATImplementNLSErrorClass(CATFileError); |
The macros create the class at build time.
You can also want to pass useful parameters to your callers, for example those that you use to fill in the message associated with the error such as the name of the file in error. Using these parameters values, the callers may decide what to do. Create such as class as follows:
#include "CATResourceError.h" class CATFileError : public CATResourceError { public: CATDeclareError(CATFileError, CATResourceError) CATFileError(const char * iMsgId, const char * iMsgCatalog, char * iFileName); HRESULT SetFileName(char * iFileName); HRESULT GetFileName(char ** oFileName); private: char * _FileName; }; |
The source file of this class could be as follows:
#include "CATFileError.h" CATImplementError(CATFileError, CATResourceError); CATImplementNLSErrorClass(CATFileError); CATFileError::CATFileError(const char * iMsgId, const char * iMsgCatalog, char * iFileName) : CATResourceError(const char * iMsgId, const char * iMsgCatalog) { _FileName = iFileName; } HRESULT CATFileError::SetFileName(char * iFileName) { _FileName = iFileName; CATReturnSuccess; } HRESULT CATFileError::GetFileName(char ** oFileName) { if (NULL != oFileName) { *oFileName = _FileName; CATReturnSuccess; } else CATReturnFailure; } |
[Top]
Error class instances can be associated with returned HRESULTs or exceptions, along with an error
identifier and a message that can include parameters values from the method current state.
If the method is located at the appropriate level, a prompt can be issued to the end user.
Errors can be traced using the CATSysLogAbend
and CATSysLogError
macros. If necessary, new error messages and new error classes can be created.
[Top]
[1] | CAA V5 Error Processing Rules |
[2] | Managing Errors Using HRESULT |
[3] | Managing Errors Using Exceptions |
[Top]
Version: 1 [Nov 2001] | Document created |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.