Confdump Agent  1.4.0
errors.cpp
Go to the documentation of this file.
00001 /* 
00002  * Confdump-Agent - Dump static and runtime system configuration
00003  * Copyright (C) 2009-2012  Straton IT, SAS
00004  * 
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  * 
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  * 
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00018 #include <comdef.h>
00019 #include <wbemidl.h>
00020 
00021 #include "boost/type_traits/make_unsigned.hpp"
00022 #include "Confdump/System/Wmi/errors.hpp"
00023 
00024 using boost::shared_ptr;
00025 
00026 namespace Confdump
00027 {
00028 namespace System
00029 {
00030 namespace Wmi
00031 {
00032 
00033 Win32Error::Win32Error( QString message, HRESULT hr )
00034  : RuntimeError( message ), hresult_( hr )
00035 {
00036 }
00037 
00038 Win32Error::~Win32Error()
00039 {
00040 }
00041 
00042 HRESULT Win32Error::hresult() const
00043 {
00044     return hresult_;
00045 }
00046 
00047 QString Win32Error::hresultAsHex() const
00048 {
00049     // HRESULT is signed so that failures are <0. Reinterpret its bit pattern
00050     // as not signed for display purposes.
00051     typedef boost::make_unsigned<HRESULT>::type Uhresult;
00052     Uhresult uvalue = *reinterpret_cast<const Uhresult*>( &hresult_ );
00053     return "0x" + QString::number( uvalue, 16 );
00054 }
00055 
00056 
00057 
00058 
00059 ComError::ComError( HRESULT hr, QString action )
00060  : Win32Error( "ComError", hr ), comError_( hr )
00061 {
00062     setMessage( QString( "Failed to %1: %2 (%3)." )
00063                                 .arg( action ).arg( errorMessage() ).arg( hresultAsHex() ) );
00064 }
00065 
00066 ComError::~ComError()
00067 {
00068 }
00069 
00070 QString ComError::errorMessage() const
00071 {
00072     return QString::fromWCharArray( comError_.ErrorMessage() );
00073 }
00074 
00075 WmiError::WmiError( QString statusDump, HRESULT hr, QString action )
00076  : Win32Error( "WmiError", hr )
00077 {
00078         WmiDiagnostics diag( hr );
00079         
00080     setMessage( QString( "Failed to %1. Error code %3, extended info: %2\n"
00081                                         "Possible cause: %4\n" )
00082                                 .arg( action ).arg( statusDump ).arg( hresultAsHex() )
00083                                 .arg( diag.knownError() ? diag.toString() : "" ) );
00084 }
00085 
00086 WmiError::~WmiError()
00087 {
00088 }
00089 
00090 
00091 
00092 void throwOnWmiError( HRESULT hr, QString action, QString element )
00093 {
00094         /* Implementation note: this code is ugly, but the throwOn*Error mechanism
00095          * can't be used here. There is only one exception of interest that may be
00096          * thrown here: whatever caused throwOnWmiError() to be called in the first
00097          * place.
00098          */
00099     if ( FAILED( hr ) )
00100     {
00101                 // First get an ErrorInfo. Not useful as such because its Description is empty.
00102         IErrorInfo *rawError = 0;
00103         if ( GetErrorInfo( 0, &rawError ) == S_OK )
00104         {
00105                         shared_ptr<IErrorInfo> error = guardComObject( rawError );
00106                         
00107                         // From there, get a WMI object with useful hints in its properties
00108                         IWbemClassObject *rawStatus = 0;
00109                         if ( error->QueryInterface( IID_IWbemClassObject,
00110                                 reinterpret_cast<void**>( &rawStatus ) ) == S_OK )
00111                         {
00112                                 shared_ptr<IWbemClassObject> status = guardComObject( rawStatus );
00113                                 
00114                                 // Usually this is an __ExtendedStatus, but we're not sure and don't
00115                                 // really want to dive into it, so let's just dump it to the user
00116                                 BSTR rawText;
00117                                 if ( status->GetObjectText( 0, &rawText ) == S_OK )
00118                                 {
00119                                         _bstr_t text( rawText );
00120                                         throw WmiError( QString::fromWCharArray( text, text.length() ),
00121                                                 hr, action );
00122                                 }
00123                         }
00124         }
00125         
00126         throwOnComError( hr, action ); // Fallback if no WMI error found
00127     }
00128 }
00129 
00130 void throwOnComError( HRESULT hr, QString action )
00131 {
00132         if ( FAILED( hr ) )
00133         throw ComError( hr, action );
00134 }
00135 
00136 
00137 WmiDiagnostics::WmiDiagnostics( HRESULT hr )
00138  : hr_( hr )
00139 {
00140         switch ( hr )
00141         {
00142         case 0x80041014: // "failed to initialize component for internal reasons"
00143                 cause_ = "Query results too large for this computer";
00144                 break;
00145         case 0x80041024:
00146                 cause_ = "WMI class is not enumerable";
00147                 break;
00148         case 0x80041003:
00149                 cause_ = "Access denied";
00150                 break;
00151         }
00152 }
00153 
00154 bool WmiDiagnostics::knownError() const
00155 {
00156         return !cause_.isNull();
00157 }
00158 
00159 QString WmiDiagnostics::toString() const
00160 {
00161         return cause_;
00162 }
00163 
00164 
00165 }
00166 }
00167 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends