2009-04-01 5 views
3

Lors de l'implémentation d'une interface COM, j'attribue toujours les paramètres out en cas de succès mais devrais-je le faire également en cas d'erreur?Les paramètres de sortie doivent-ils être définis même si la fonction COM échoue?

HRESULT CDemo::Div(/*[in]*/ LONG a, /*[in]*/LONG b, /*[out,retval]*/ LONG* pRet) 
{ 
    if (pRet == NULL) 
     return E_POINTER; 

    if (b == 0) 
    { 
     *pRet = 0; // is this redundant? 
     return E_INVALIDARG; 
    } 

    *pRet = a/b; 
    return S_OK; 
} 

À un moment donné, j'étais un peu sur le nez de ne pas initialiser un paramètre out et en supposant que si j'initialisés la variable il reste que la valeur si je ne change pas à l'intérieur de la méthode. Cependant, j'ai utilisé cette méthode de .NET et puisque le marshaller voit que c'est un paramètre [out] il a rejeté la valeur initiale que j'ai placé sur le site d'appel et mis dans la poubelle après la fonction retournée (c'était amusant de déboguer cela, pas).

Attribue un out param même en cas de surcompensation de panne ou devrais-je vraiment le faire?


Edit: Même si on ne doit pas accéder formellement à params si la fonction a échoué, je vois souvent (et parfois écrire) code comme ceci (en utilisant l'exemple de sharptooth's post):

ISmth *pSmth = NULL; 
pObj->GetSmth(&pSmth); // HRES is ignored 
if (pSmth) // Assumes that if GetSmth failed then pSmth is still NULL 
{ 
    pSmth->Foo(); 
    pSmth->Release(); 
} 

Cela fonctionne bien dans le code non-marshalled (même thread apartment) mais si un marshaller est impliqué est-il assez intelligent pour seulement définir la valeur de retour si la fonction a réussi?

+0

Je pense que cela ne devrait pas avoir d'importance. Le client COM appelant ne doit pas regarder le paramètre 'out' en cas d'échec. –

Répondre

3

Alors que les autres réponses ne sont pas fausses, ils manquent un point très important - un serveur COM qui a l'intention de retourner un échec HRESULT DOIT définir tous les paramètres [out] à NULL. Ce n'est pas seulement une question de bon style, cela est exigé par COM et ne pas y adhérer peut causer des accidents aléatoires lorsqu'il y a du marshaling impliqué.

Ceci étant dit, le * pRet = 0; dans le code d'origine n'est pas redondant mais correct et nécessaire.

+0

Pouvez-vous fournir une référence à cette réclamation? – Motti

+0

COM efficace, élément 19: Toujours initialiser les paramètres [out]. Doivent être enterrés quelque part dans la spécification COM aussi ... –

+0

http://msdn.microsoft.com/fr-fr/library/windows/desktop/ms686638(v=vs.85).aspx –

3

La règle est que l'appelant n'est pas autorisé à faire quoi que ce soit avec la valeur des paramètres out si l'appel échoue. Le serveur ne doit donc pas fournir de valeurs valides et ne doit pas transmettre la propriété de toutes les ressources aux paramètres out.

Par exemple, si vous avez

HRESULT GetSmth([out] ISmth**); 
méthode

il est prévu que le serveur appelle AddRef() sur la variable ISmth** avant de retourner. Il ne doit pas appeler AddRef() s'il doit renvoyer un code d'échec car le client n'est pas autorisé à utiliser la valeur du paramètre renvoyé et n'appelle donc pas Release() et vous aurez une fuite de mémoire.

1

Je ne suis pas sûr que je suis entièrement d'accord avec sharptooth. Je suis tout à fait d'accord avec le fait que pour un appel COM qui a échoué, vous ne pouvez pas et ne devez assigner aucune propriété à aucun paramètre out. Cela inclut l'allocation de mémoire ou AddRef'ing un objet COM.

Cependant, je ne vois rien de mal (et en fait encourage) à définir des paramètres purement externes pour vider des valeurs tant que cela ne transfère aucune propriété de ressources. Par exemple, il n'y a rien de techniquement illégal à propos de votre code de réglage pRet pour pointer sur 0. Cela ne transfère pas la propriété des ressources à pRet et est simplement une aide pour un appelant qui n'a pas vérifié correctement le succès de l'appel.

Questions connexes