92 votes

Comment utiliser correctement FormatMessage() en C++ ?

Sans :

  • MFC
  • ATL

Comment puis-je utiliser FormatMessage() pour obtenir le texte d'erreur d'une HRESULT ?

 HRESULT hresult = application.CreateInstance("Excel.Application");

 if (FAILED(hresult))
 {
     // what should i put here to obtain a human-readable
     // description of the error?
     exit (hresult);
 }

136voto

Shog9 Points 82052

Voici la manière correcte d'obtenir un message d'erreur de la part du système pour une HRESULT :

LPTSTR errorText = NULL;

FormatMessage(
   // use system message tables to retrieve error text
   FORMAT_MESSAGE_FROM_SYSTEM
   // allocate buffer on local heap for error text
   |FORMAT_MESSAGE_ALLOCATE_BUFFER
   // Important! will fail otherwise, since we're not 
   // (and CANNOT) pass insertion parameters
   |FORMAT_MESSAGE_IGNORE_INSERTS,  
   NULL,    // unused with FORMAT_MESSAGE_FROM_SYSTEM
   hresult,
   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   (LPTSTR)&errorText,  // output 
   0, // minimum size for output buffer
   NULL);   // arguments - see note 

if ( NULL != errorText )
{
   // ... do something with the string - log it, display it to the user, etc.

   // release memory allocated by FormatMessage()
   LocalFree(errorText);
   errorText = NULL;
}

La principale différence entre cette réponse et celle de David Hanak est l'utilisation de l'option FORMAT_MESSAGE_IGNORE_INSERTS drapeau. MSDN est un peu flou sur la façon dont les insertions doivent être utilisées, mais Raymond Chen note que vous ne devriez jamais les utiliser lors de la récupération d'un message système, car vous n'avez aucun moyen de savoir quelles insertions le système attend.

Pour info, si vous utilisez Visual C++, vous pouvez vous faciliter la vie en utilisant la fonction _com_error classe :

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

Il ne fait pas partie du MFC ou de l'ATL directement, pour autant que je sache.

14voto

Marius Points 2008

Gardez à l'esprit que vous ne pouvez pas faire ce qui suit :

{
   LPCTSTR errorText = _com_error(hresult).ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

Au fur et à mesure que la classe est créée et détruite sur la pile, laissant errorText pointer vers un emplacement invalide. Dans la plupart des cas, cet emplacement contiendra toujours la chaîne d'erreur, mais cette probabilité disparaît rapidement lors de l'écriture d'applications threadées.

Alors toujours faites comme suit, comme répondu par Shog9 ci-dessus :

{
   _com_error error(hresult);
   LPCTSTR errorText = error.ErrorMessage();

   // do something with the error...

   //automatic cleanup when error goes out of scope
}

11voto

David Hanak Points 5960

Essayez ça :

void HandleLastError(const char *msg /* = "Error occured" */) {
        DWORD errCode = GetLastError();
        char *err;
        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                           NULL,
                           errCode,
                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
                           (LPTSTR) &err,
                           0,
                           NULL))
            return;

        //TRACE("ERROR: %s: %s", msg, err);
        static char buffer[1024];
        _snprintf(buffer, sizeof(buffer), "ERROR: %s: %s\n", msg, err);
        OutputDebugString(buffer);
        LocalFree(err);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X