Useful macros
Below are some macros that can make a developer's life a bit easier because they help to track down bugs and errors and also provide a convenient way to control the program flow.
Knowing more about leaves
#define LOGLEAVE(err) MyLogger::Write("%s:%d, %s : leave (%d)", __FILE__, __LINE__, __PRETTY_FUNCTION__, err)
#define LEAVE(err) {LOGLEAVE(err); User::Leave(err);}
#define LEAVEIFERROR(exp) ({volatile TInt err = exp; (err >= 0) || ((LEAVE(err)), 0);})
It may be useful to replace all calls to User::Leave()and User::LeaveIfError() with the macros LEAVE and LEAVEIFERROR defined above. In this case before the actual leave occurs you will have all the information about it logged.
If you do not create a logger in your program then you can use RDebug::Printf() on emulator. In this case you need to change the LOGLEAVE definition as follows:
#ifdef _DEBUG
#define LOGLEAVE(err) RDebug::Printf("%s:%d, %s : leave (%d)", \
__FILE__, __LINE__, __PRETTY_FUNCTION__, err)
#else #define LOGLEAVE(err)
#endif
Having done so you will get the log output in epocwind.out located in current user's temp directory (C:\Documents and Settings\<user_id>\Local Settings\Temp).
Also you can pay your attention to TRAP_INSTRUMENTATION_XXX macros defined in e32cmn.h. For example you can do the following way:
#undef TRAP_INSTRUMENTATION_LEAVE
#define TRAP_INSTRUMENTATION_LEAVE(err) LOGLEAVE(err)
The above means that every trapped leave will also be logged.
Extending asserts
There are useful assert-macros defined in e32def.h but you can add some more:
#define __ASSERT_RETURN(c, err) if(!c) return err;
#define __ASSERT_LEAVE(c, err) ((c) || ((LEAVE(err)), 0))
#ifdef _DEBUG
#define __ASSERT_RETURN_D(c, err) __ASSERT_RETURN(c, err)
#define __ASSERT_LEAVE_D(c, err) __ASSERT_LEAVE(c, err)
#else #define __ASSERT_RETURN_D(c, err)
#define __ASSERT_LEAVE_D(c, err)
#endif
__ASSERT_RETURN asserts that condition c is true; if it is false than the function returns err.
__ASSERT_LEAVE asserts that condition c is true; if it is false than the function leaves with reason code err.
__ASSERT_RETURN_D and __ASSERT_LEAVE_D are versions that are generated in debug builds only.
Examples
Example 1
LEAVEIFERROR(iFile.Open(iFsSession, aFileName, EFileWrite | EFileShareAny));
If in the example above the call to RFile::Open() fails you will get in your log something like this:
myfilemanager.cpp:279, CMyFileManager::OpenFileL(const TDesC16&) : leave (-1)
Example 2
TRAPD(err, DoSomethingL());
In case of a leave the code above will produce the following record in log:
myfile.cpp:24, CMyClass::DoSomethingL(int ) : leave (-6)
Example 3
TInt DoSomething(TInt aArg)
{
__ASSERT_RETURN(aArg > 0, KErrArgument);
Here DoSomething() will return KErrArgument if aArg is less than zero.
Example 4
void DoSomethingL(TInt aArg)
{
__ASSERT_LEAVE(aArg > 0, KErrArgument);
In this example DoSomethingL() will leave with KErrArgument if aArg is less than zero producing the following entry in log file:
myfile.cpp:24, CMyClass::DoSomethingL(int ) : leave (-6)