OVH Cloud OVH Cloud

Exceptions

3 réponses
Avatar
Michael
Bonjour à tous,

j'ai un petit souci avec la gestion d'exceptions pour une bibliothèque que
je suis en train de créer, servant de wrapper à DirectShow.

Initialement, avant de me décider à faire quelque chose de vraiment
"propre", j'avais ça:

//------------------------------------------
//Problème lors d'un QueryInterface
class EDS_Bad_Init : public Exception
{
public:
__fastcall EDS_Bad_Init(const AnsiString & nom_filter)
{
Language *Lang = Language::getInstance();
Message = Lang->Get_Sequence(9) + " " + nom_filter;
}
};

//----------------------------------------------------------------------
//Problème lors d'un AddFilter
class EDS_Cannot_Add : public Exception
{
public:
__fastcall EDS_Cannot_Add(const AnsiString & nom_filter)
{
Language *Lang = Language::getInstance();
Message = Lang->Get_Sequence(25) + " " + nom_filter;
}
};

//-----------------------------------------------------------------------
//Problème lors de connection entre deux pins / filters
class EDS_Bad_Connect : public Exception
{
public:
__fastcall EDS_Bad_Connect(const AnsiString & nom_input, const
AnsiString & nom_output)
{
Language *Lang = Language::getInstance();
Message = Lang->Get_Sequence(27) + " " + nom_input + " -> " +
nom_output;
}
};

namespace DSE
{
void DS_Bad_Init(HRESULT hr, const AnsiString & filterName)
{
if FAILED(hr)
throw (EDS_Bad_Init(filterName));
}

void DS_Cannot_Add(HRESULT hr, const AnsiString & filterName)
{
if FAILED(hr)
throw (EDS_Cannot_Add(filterName));
}

void DS_Bad_Connect(HRESULT hr, const AnsiString & inputName,
const AnsiString & outputName)
{
if FAILED(hr)
throw (EDS_Bad_Connect(inputName,outputName));
}
}

Et dans le code de la bibliothèque, j'utilisais tout ça comme suit:

DSE::DS_Bad_Init(pGraph->QueryInterface(IID_IMediaControl, (void **)
&pControl),"IMediaControl");

DSE::DS_Bad_Connect(pRender->SetTimelineObject(pTL),"pTimeline","pRender");

DSE::DS_Cannot_Add(pGraph->AddFilter(pVmr, L"Video Mixing Renderer
9"),"Video Mixing Renderer 9");

Le souci avec tout ça, c'est l'appel à la classe Language, qui est un
singleton permettant de récupérer une chaine de caractères dans un fichier
XML...

Si on prend l'exemple DSE::DS_Bad_Connect(pRender->SetTimelineObject
(pTL),"pTimeline","pRender");, la chaine Message construite dans le
constructeur de la classe devient EDS_Bad_Connect:

Erreur - DirectShow : Impossible de connecter pTimeline -> pRender

Cette méthode impose qu'il existe un fichier XML avec toutes les chaines de
caractère dont peut avoir la bibliothèque pour expliciter les erreurs
qu'elle rencontre, ce qui n'est clairement pas une bonne chose. D'autant
que si le fichier n'existe pas, la bibliothèque est inutilisable.

Donc ce que je voulais savoir, c'est la manière dont une bibliothèque doit
gèrer les exceptions.

Est-ce que je dois utiliser du code comme ça:

if (FAILED(pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl)))
throw BadInit(IMediaControl);

if (FAILED(pRender->SetTimelineObject(pTL)))
throw BadConnect("pTimeline","pRender");

if (FAILED(pGraph->AddFilter(pVmr, L"Video Mixing Renderer 9")))
throw CannotAdd("Video Mixing Renderer 9");

Et c'est à l'utilisateur de la bibliothèque de gérer toutes les exceptions
possibles à chaque fois qu'il l'utilise?

Ou bien on ne doit laisser à l'utilisateur que la possibilité de gérer les
exceptions sur lesquelles il peut réellement agir?

En effet, je peux différencier des exceptions internes à la bibliothèque
(comme les 3 exemples cités) sur lesquels l'utilisateur ne peut rien faire,
et des exceptions sur lesquelles il est possible d'agir (comme par exemple
l'impossibilité de trouver un fichier vidéo qu'on veut lire...)

Comment je gère ça aussi?

En bref, comment faites vous?

Merci d'avance pour vos conseils

Mike

3 réponses

Avatar
Jean-Marc Bourguet
Michael <michael.at.gmail.dot.com> writes:

Merci d'avance pour vos conseils


* Utiliser des exceptions quand l'erreur doit etre traitee par
quelqu'un d'autre que l'appelant, un code d'erreur quand l'exception
doit etre traitee par l'appelant direct (a chaque fois, il faut
considerer la frontiere entre sous-systeme). Il y a une troisieme
possibilite: appeler une fonction gestionnaire d'erreur enregistree
par l'utilisateur.

* Separer le report des erreurs du formatage d'un eventuel message.
Les exceptions, les codes d'erreurs transmettent une description
logique du probleme. Si l'utilisateur veut le formater, il s'en
occupe tout seul comme un grand (on peut prevoir dans la bibliotheque
un moyen de le faire, mais c'est un service separe des exceptions et
des codes d'erreurs).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Michael
* Utiliser des exceptions quand l'erreur doit etre traitee par
quelqu'un d'autre que l'appelant, un code d'erreur quand l'exception
doit etre traitee par l'appelant direct (a chaque fois, il faut
considerer la frontiere entre sous-systeme). Il y a une troisieme
possibilite: appeler une fonction gestionnaire d'erreur enregistree
par l'utilisateur.


Je ne comprends pas très bien ce que tu entends par appellant...
L'utilisateur de la bibliothèque?

* Separer le report des erreurs du formatage d'un eventuel message.
Les exceptions, les codes d'erreurs transmettent une description
logique du probleme. Si l'utilisateur veut le formater, il s'en
occupe tout seul comme un grand (on peut prevoir dans la bibliotheque
un moyen de le faire, mais c'est un service separe des exceptions et
des codes d'erreurs).


OK, c'est bien ce que je pensais...

Merci

Avatar
Jean-Marc Bourguet
Michael <michael.at.gmail.dot.com> writes:

Je ne comprends pas très bien ce que tu entends par appellant...
L'utilisateur de la bibliothèque?


Oui.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org