summaryrefslogtreecommitdiffstats
path: root/doc/src/symbian-exceptionsafety.qdoc
blob: 56b28c9828f7c89e3909d511a0d595e86278fbdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \page symbianexceptionsafety.html
    \title Exception Safety with Symbian
    \ingroup qts60
    \brief A guide to integrating exception safety in Qt with Symbian.

    The following sections describe how Qt code can interoperate with Symbian's
    exception safety system.

    \tableofcontents

    \section1 What the problem is
    
    Qt and Symbian have different exception systems. Qt works with standard C++ 
    exceptions, whereas Symbian has its TRAP/Leave/CleanupStack system. So, what would 
    happen if you mix the two systems? It could go wrong in a number of ways.

    Clean-up ordering would be different between the two. When Symbian code 
    leaves, the clean-up stack is cleaned up before anything else happens. After 
    that, the objects on the call stack would be cleaned up as with a normal 
    exception. So if there are any dependencies between stack-based and  
    objects owned by the clean-up stack, there could be problems due to this
    ordering.

    Symbian's \c XLeaveException, which is used when Symbian implements leaves as 
    exceptions, is not derived from \c std::exception, so would not be caught in 
    Qt catch statements designed to catch \c std::exception. 

    Qt's and standard C++'s \c std::exception derived exceptions result in program 
    termination if they fall back to a Symbian TRAP. 

	These problems can be solved with barrier macros and helper functions that 
	will translate between the two exception systems. Use them, in Qt code, 
	whenever calling into or being called from Symbian code.

    \section1 Qt calls to Symbian

    When calling Symbian leaving functions from Qt code, we want to translate 
    Symbian leaves to standard C++ exceptions. The following help is provided:

    \list
        \o \l qt_translateSymbianErrorToException() takes a Symbian
        error code and throws an appropriate exception to represent it. 
        This will do nothing if the error code is not in fact an error. The 
        function is equivalent to Symbian's \c User::LeaveIfError.
        \o \l QT_TRANSLATE_SYMBIAN_LEAVE_TO_EXCEPTION() takes a Symbian leaving
        code fragment f and runs it under a trap harness converting any resulting 
        error into an exception.
        \o \c TRAP and \c TRAPD from the Symbian libraries can be used to convert 
        leaves to error codes. 
    \endlist

    \code
    HBufC* buf=0;
    // this will throw a std::bad_alloc because we've asked for too much memory
    QT_TRANSLATE_SYMBIAN_LEAVE_TO_EXCEPTION(buf = HBufC::NewL(100000000));

    _LIT(KStr,"abc");
    TInt pos = KStr().Locate('c');
    // pos is a good value, >= 0, so no exception is thrown
    qt_translateSymbianErrorToException(pos);
    
    pos = KStr().Locate('d');
    // pos == KErrNotFound, so this throws an exception
    qt_translateSymbianErrorToException(pos);
    \endcode
    
    \section1 Qt called from Symbian

    When Qt code is called from Symbian, we want to translate standard C++ 
    exceptions to Symbian leaves or error codes. The following help is 
    provided:

    \list
        \o \l qt_translateExceptionToSymbianError() -
        this takes a standard exception and gives an appropriate Symbian 
        error code. If no mapping is known for the exception type, 
        \c KErrGeneral is returned.
        \o \l qt_translateExceptionToSymbianErrorL() -
        this takes a standard exception and generates an appropriate Symbian 
        leave.
        \o \l QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_ERROR() - this macro
        takes the standard C++ code fragment \c f, catches any std::exceptions 
        thrown from it, and sets err to the corresponding Symbian error code. 
        err is set to \c KErrNone otherwise.
        \o \l QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_LEAVE() - this macro takes the
        standard C++ code fragment \c f, catches any std::exceptions thrown from 
        it, and throws a corresponding Symbian leave. 
    \endlist
    
    \code
    TInt DoTickL() // called from an active object RunL, ie Symbian leaves expected
        {
        // without the translation to Symbian Leave, we get a USER:0 panic
        QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_LEAVE({
            int* x = new int[100000000];            // compiled as Qt code, will throw std::bad_alloc
            delete [] x;
        });
        return 0;
        }
    \endcode

    \section1 Common sense things

    Try to minimise the interleaving of Symbian and Qt code, every switch 
    requires a barrier. Grouping the code styles in different blocks will 
    minimise the problems. For instance, examine the following code.

    \code
    1.    TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this);
    2.               QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath();
    3.               filepath = QDir::toNativeSeparators(filepath);
    4.               m_playUtility->OpenFileL(qt_QString2TPtrC(filepath)));
    \endcode

    Line 1 starts a Symbian leave handling block, which is good because it 
    also uses a Symbian leave generating function.

    Line 2 creates a \l QString, uses \l QFileInfo and various member functions. 
    These could all throw exceptions, which is not good inside a \c TRAP block.

    Line 3 is unclear as to whether it might throw an exception, but since 
    it's dealing with strings it probably does, again bad.

    Line 4 is tricky, it calls a leaving function which is ok within a \c TRAP, 
    but it also uses a helper function to convert string types. In this case
    the helper function may cause an unwelcome exception.

    We could rewrite this with nested exception translations, but it's much 
    easier to refactor it. 

    \code
    QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath();
    filepath = QDir::toNativeSeparators(filepath);
    TPtrC filepathPtr(qt_QString2TPtrC(filepath));
    TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this);
               m_playUtility->OpenFileL(filepathPtr));
    \endcode

    Now the exception generating functions are separated from the leaving 
    functions.
*/