Confdump Agent
1.4.0
|
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 }