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 <algorithm> 00022 00023 #include "boost/foreach.hpp" 00024 00025 #include "QVariant" 00026 #include "QList" 00027 #include "QString" 00028 00029 #include "Confdump/System/WmiDumper.hpp" 00030 #include "Confdump/System/ManagedElement.hpp" 00031 #include "Confdump/System/Wmi/ComContext.hpp" 00032 #include "Confdump/System/Wmi/WbemServices.hpp" 00033 #include "Confdump/System/Wmi/errors.hpp" 00034 00035 using namespace Confdump::System::Wmi; 00036 using boost::shared_ptr; 00037 00038 /* Design notes: the "iterate over WMI Object properties" and "iterate over 00039 * SafeArray elements" parts could easily be abstracted as custom iterators. 00040 * However, they are unlikely to need much maintenance in the future so it 00041 * seems like an useless investment right now. 00042 * 00043 * -T. Equeter, 2011-09. 00044 */ 00045 00046 namespace 00047 { 00048 00049 QVariant bstrToQVariant( _bstr_t str ) 00050 { 00051 return QString::fromWCharArray( str, str.length() ); 00052 } 00053 00055 QVariant variantToQVariant( _variant_t value ) 00056 { 00057 if ( V_VT( &value ) & VT_ARRAY ) 00058 { 00059 try { 00060 value.ChangeType( VT_ARRAY|VT_BSTR ); 00061 } 00062 catch( _com_error& ) 00063 { 00064 return QVariant(); 00065 } 00066 00067 HRESULT hr; 00068 SAFEARRAY *arr = V_ARRAY(&value); // variant still owns the array 00069 00070 LONG lStart = 0; 00071 hr = SafeArrayGetLBound(arr, 1, &lStart); 00072 throwOnComError( hr, "get the lower bound of a WMI object array attribute" ); 00073 00074 LONG lEnd = 0; 00075 hr = SafeArrayGetUBound(arr, 1, &lEnd); 00076 throwOnComError( hr, "get the upper bound of a WMI object array attribute" ); 00077 00078 BSTR HUGEP *elements; 00079 hr = SafeArrayAccessData( arr, reinterpret_cast<void HUGEP**>( &elements ) ); 00080 throwOnComError( hr, "access a WMI object array attribute" ); 00081 shared_ptr<SAFEARRAY> arrayAccessGuard( arr, SafeArrayUnaccessData ); 00082 00083 QList<QVariant> qlist; 00084 std::transform( &elements[lStart], &elements[lEnd+1], std::back_inserter( qlist ), bstrToQVariant ); 00085 00086 return qlist; 00087 } 00088 else // if ( valueType != VT_NULL && valueType != VT_EMPTY ) 00089 { 00090 try { 00091 _bstr_t str = value; 00092 return QString::fromWCharArray( str, str.length() ); 00093 } 00094 catch( _com_error& ) 00095 { 00096 return QVariant(); 00097 } 00098 } 00099 } 00100 00101 } // ns 00102 00103 00104 Confdump::System::WmiDumper::WmiDumper() 00105 { 00106 initWbemServices(); 00107 services_->connect(); 00108 } 00109 00110 Confdump::System::WmiDumper::WmiDumper( QString wmiNamespace ) 00111 { 00112 initWbemServices(); 00113 services_->setWmiNamespace( wmiNamespace ); 00114 services_->connect(); 00115 } 00116 00117 Confdump::System::WmiDumper::~WmiDumper() 00118 { 00119 } 00120 00121 void Confdump::System::WmiDumper::initWbemServices() 00122 { 00123 ComContext::Guard guard = ComContext().getGuard(); 00124 services_.reset( new Wmi::WbemServices( guard ) ); 00125 } 00126 00127 Confdump::Result Confdump::System::WmiDumper::doQueryTable( QString table ) 00128 { 00129 Result result; 00130 HRESULT hr; 00131 00132 Query query("*", table.toStdString(), ""); 00133 BOOST_FOREACH( boost::shared_ptr<IWbemClassObject> object, services_->execQuery( query ) ) 00134 { 00135 boost::shared_ptr<ManagedElement> row( new ManagedElement ); 00136 00137 hr = object->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY); 00138 throwOnWmiError( hr, "enumerate WMI object properties" ); 00139 00140 for ( ;; ) 00141 { 00142 BSTR rawName; 00143 VARIANT rawValue; 00144 hr = object->Next( 0, &rawName, &rawValue, 0, 0 ); 00145 throwOnWmiError( hr, "iterate over WMI object properties" ); 00146 if ( hr == WBEM_S_NO_MORE_DATA ) 00147 break; 00148 00149 _bstr_t name = _bstr_t( rawName, false ); // take ownership 00150 _variant_t value = _variant_t( rawValue, false ); // take ownership 00151 00152 QVariant qvalue = variantToQVariant( value ); 00153 row->setProperty( name, qvalue ); 00154 } 00155 result.addRow( row ); 00156 } 00157 00158 return result; 00159 } 00160 00161 QString Confdump::System::WmiDumper::doComputerIdentifier() 00162 { 00163 Result computers = queryTable( "Win32_ComputerSystemProduct" ); 00164 if ( computers.begin() != computers.end() ) 00165 return (*computers.begin())->property( "UUID" ).toString(); 00166 else 00167 return QString(); 00168 } 00169 00170 QStringList Confdump::System::WmiDumper::doListTables() 00171 { 00172 QStringList tables; 00173 00174 BOOST_FOREACH( boost::shared_ptr<IWbemClassObject> object, services_->listAllClasses() ) 00175 { 00176 VARIANT rawValue; 00177 HRESULT hr = object->Get( L"__CLASS", 0, &rawValue, 0, 0 ); 00178 throwOnWmiError( hr, "get the enumerated class name" ); 00179 _variant_t value = rawValue; 00180 00181 try { 00182 _bstr_t strValue = value; 00183 tables.push_back( QString::fromWCharArray( strValue, strValue.length() ) ); 00184 } 00185 catch ( _com_error& ) 00186 { 00187 throw RuntimeError( "Unexpected type for an enumerated WMI class name, couldn't cast it to string" ); 00188 } 00189 } 00190 00191 return tables; 00192 } 00193