Confdump Agent  1.4.0
WmiDumper.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 <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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends