SmbiosStrategy_Windows.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
00003  *
00004  * Copyright (C) 2005 Dell Inc.
00005  *  by Michael Brown <Michael_E_Brown@dell.com>
00006  * Licensed under the Open Software License version 2.1
00007  *
00008  * Alternatively, you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published
00010  * by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012 
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  */
00018 
00019 // compat header should always be first header if including system headers
00020 #define LIBSMBIOS_SOURCE
00021 #include "smbios/compat.h"
00022 
00023 #include <iostream>
00024 #include <sstream>
00025 
00026 /* stuff for WMI. needs SDK, so is optional. */
00027 #ifdef LIBSMBIOS_WIN_USE_WMI
00028 #   ifndef _WIN32_DCOM
00029 #   define _WIN32_DCOM
00030 #   endif
00031 
00032 // this pragma statment will automatically add the 'wbemuuid.lib' library
00033 // to program library link list
00034 #  pragma comment(lib, "wbemuuid")
00035 
00036 #   include <objbase.h>
00037 #   include <wbemcli.h>
00038 #endif
00039 
00040 #include "smbios/IMemory.h"
00041 #include "SmbiosImpl.h"
00042 #include "miniddk.h"
00043 
00044 // message.h should be included last.
00045 #include "smbios/message.h"
00046 
00047 using namespace smbiosLowlevel;
00048 using namespace std;
00049 
00050 namespace smbios
00051 {
00052     // Non Member Functions
00053     GetSystemFirmwareTablePtr GetSystemFirmwareTable = 0;
00054 
00055     int LoadNtdllFuncs(void)
00056     {
00057         HMODULE hKerneldll;
00058 
00059         hKerneldll = GetModuleHandle( "kernel32.dll" );
00060         if (!hKerneldll)
00061             return FALSE;
00062 
00063         // Donot return false since these APIs are only available on W2K3 SP1 and higher.
00064         // returning FALSE will break libsmbios on W2K and W2K3( no SP )
00065         GetSystemFirmwareTable = (GetSystemFirmwareTablePtr) GetProcAddress(hKerneldll, "GetSystemFirmwareTable");
00066 
00067         return TRUE;
00068     }
00069 
00070 
00071     bool SmbiosWinGetFirmwareTableStrategy::getSmbiosTable(const u8 **smbiosBuffer, smbiosLowlevel::smbios_table_entry_point *table_header, bool )
00072     {
00073         // new throws exception, no need to test.
00074         u8 *newSmbiosBuffer = 0;
00075 
00076         DWORD iSignature =             'R'; //RSMB
00077         iSignature = iSignature << 8 | 'S';
00078         iSignature = iSignature << 8 | 'M';
00079         iSignature = iSignature << 8 | 'B';
00080 
00081         if( !GetSystemFirmwareTable )
00082             if( !LoadNtdllFuncs() )
00083                 throw ParseExceptionImpl( _("Could not load dll functions.") );
00084 
00085         if( !GetSystemFirmwareTable )
00086             throw ParseExceptionImpl( _("Could not access GetSystemFirmwareTable() API.") );
00087 
00088         int iBufferSizeNeeded = GetSystemFirmwareTable( iSignature, 0, 0, 0 );
00089         if( iBufferSizeNeeded <= 0 )
00090             throw ParseExceptionImpl( _("GetSystemFirmwareTable returned 0 for table length.") );
00091 
00092         newSmbiosBuffer = new u8[iBufferSizeNeeded];
00093         if( ! newSmbiosBuffer )
00094             throw ParseExceptionImpl( _("Failed to allocate memory for Firmware table.") );
00095         memset( newSmbiosBuffer, 0, sizeof(u8) * iBufferSizeNeeded );
00096 
00097         // populate buffer with table.
00098         // Note that this is not the actual smbios table:
00099         // From MS: The layout of the data returned by the raw SMBIOS table
00100         //          provider is identical to the data returned by the
00101         //          MSSmBIOS_RawSMBiosTables WMI class.  The
00102         //          MSSmBIOS_RawSMBiosTables class is located in the root\wmi
00103         //          namespace.
00104         GetSystemFirmwareTable( iSignature, 0, newSmbiosBuffer, iBufferSizeNeeded );
00105 
00106         // Have to manually set values in header because we cannot get table entry point using this api
00107         table_header->table_length = static_cast<u16>(iBufferSizeNeeded);
00108         table_header->major_ver = newSmbiosBuffer[1];
00109         table_header->minor_ver = newSmbiosBuffer[2];
00110         table_header->table_num_structs = 9999;
00111 
00112         // get rid of header that MS tacks on.
00113 #       define MS_RSMB_HEADER_SIZE 8
00114 
00115         memmove(newSmbiosBuffer, newSmbiosBuffer + MS_RSMB_HEADER_SIZE, iBufferSizeNeeded - MS_RSMB_HEADER_SIZE);
00116         memset( newSmbiosBuffer + iBufferSizeNeeded - MS_RSMB_HEADER_SIZE, 0, MS_RSMB_HEADER_SIZE);
00117 
00118         //delete old one, if necessary
00119         if( *smbiosBuffer )
00120         {
00121             memset (const_cast<u8 *>(*smbiosBuffer), 0, sizeof (**smbiosBuffer));
00122             delete [] const_cast<u8 *>(*smbiosBuffer);
00123             *smbiosBuffer = 0;
00124         }
00125 
00126         *smbiosBuffer = (const u8 *) newSmbiosBuffer;
00127         return true;
00128     }
00129 
00130 
00131 
00132 #ifdef LIBSMBIOS_WIN_USE_WMI
00133     /* NON-MEMBER functions to help parse WMI data. */
00134     static void GetWMISMBIOSEntry( IWbemClassObject **pSmbios )
00135     {
00136         BSTR                    path = SysAllocString(L"root\\wmi");
00137         BSTR                    className = SysAllocString(L"MSSmBios_RawSMBiosTables");
00138         ULONG                   uReturned = 1;
00139         HRESULT                 hr = S_FALSE;
00140         IWbemLocator            *pLocator = NULL;
00141         IWbemServices           *pNamespace = NULL;
00142         IEnumWbemClassObject    *pEnumSMBIOS = NULL;
00143 
00144         try
00145         {
00146             hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE,
00147                                        NULL, EOAC_SECURE_REFS, NULL );
00148 
00149             if (! SUCCEEDED( hr ) )
00150                 throw InternalErrorImpl(_("CoInitializeSecurity() failed"));
00151     
00152             hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLocator );
00153     
00154             if (! SUCCEEDED( hr ) )
00155                 throw InternalErrorImpl(_("CoCreateInstance() failed for locator"));
00156     
00157             hr = pLocator->ConnectServer(path, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace );
00158             pLocator->Release();
00159     
00160             if( WBEM_S_NO_ERROR != hr )
00161                 throw InternalErrorImpl(_("ConnectServer() failed for namespace"));
00162     
00163             hr = pNamespace->CreateInstanceEnum( className, 0, NULL, &pEnumSMBIOS );
00164             pNamespace->Release();
00165     
00166             if (! SUCCEEDED( hr ) )
00167                 throw InternalErrorImpl(_("CreateInstanceEnum() failed for MSSmBios_RawSMBiosTables"));
00168     
00169             hr = pEnumSMBIOS->Next( 4000, 1, pSmbios, &uReturned );
00170             pEnumSMBIOS->Release();
00171     
00172             if ( 1 != uReturned )
00173                 throw InternalErrorImpl(_("Next() failed for pEnumSMBIOS"));
00174         }
00175         catch(const exception &)
00176         {
00177             SysFreeString(className);
00178             SysFreeString(path);
00179             throw;
00180         }
00181     }
00182 
00183 
00184     static void GetWMISMBIOSTable( IWbemClassObject *pSmbios, WMISMBIOSINFO &smbiosData )
00185     {
00186         BSTR                propName;
00187         CIMTYPE             type;
00188         VARIANT             pVal;
00189         SAFEARRAY           *parray = NULL;
00190 
00191         if ( NULL == pSmbios )
00192             throw ParseExceptionImpl( _("GetWMISMBIOSTable: NULL pointer to SMBIOS Entry specified.") );
00193 
00194         VariantInit(&pVal);
00195 
00196         propName = SysAllocString(L"SMBiosData");
00197         pSmbios->Get( propName, 0L, &pVal, &type, NULL);
00198         SysFreeString(propName);
00199 
00200         if ( ( VT_UI1 | VT_ARRAY ) != pVal.vt )
00201             throw ParseExceptionImpl( _("GetWMISMBIOSTable: SMBiosData returned unknown entry type.") );
00202 
00203         parray = V_ARRAY(&pVal);
00204 
00205         smbiosData.bufferSize = parray->rgsabound[0].cElements;
00206 
00207         if ( smbiosData.bufferSize == 0 )
00208             throw ParseExceptionImpl( _("GetWMISMBIOSTable: Buffer size was zero.") );
00209 
00210         smbiosData.buffer = new u8[smbiosData.bufferSize];
00211         if ( ! smbiosData.buffer )
00212             throw ParseExceptionImpl( _("GetWMISMBIOSTable: Failed to allocate memory for SMBIOS table.") );
00213 
00214         memcpy(smbiosData.buffer, (u8 *)parray->pvData, smbiosData.bufferSize);
00215     }
00216 
00217     static void GetWMISMBIOSVersion( IWbemClassObject *pSmbios, u8 *majorVersion, u8 *minorVersion )
00218     {
00219         BSTR            propName;
00220         HRESULT         hr = S_OK;
00221         CIMTYPE         type;
00222         VARIANT         pVal;
00223 
00224         if ( NULL == pSmbios )
00225             throw ParseExceptionImpl( _("GetWMISMBIOSVersion: null pointer passed as pSmbios.") );
00226 
00227         VariantInit( &pVal );
00228         propName = SysAllocString( L"SmbiosMajorVersion" ); 
00229         hr = pSmbios->Get( propName, 0L, &pVal, &type, NULL );
00230         SysFreeString( propName );
00231 
00232         if ( ! SUCCEEDED( hr ) || VT_UI1 != pVal.vt ) 
00233             throw ParseExceptionImpl( _("GetWMISMBIOSVersion: problem accessing WMI SmbiosMajorVersion.") );
00234 
00235         if(majorVersion)
00236             *majorVersion = V_UI1(&pVal); 
00237 
00238         VariantClear( &pVal ); 
00239         propName = SysAllocString( L"SmbiosMinorVersion" ); 
00240         hr = pSmbios->Get( propName, 0L, &pVal, &type, NULL );
00241         SysFreeString( propName );
00242 
00243         if ( !SUCCEEDED( hr ) || pVal.vt != VT_UI1 ) 
00244             throw ParseExceptionImpl( _("GetWMISMBIOSVersion: problem accessing WMI SmbiosMinorVersion.") );
00245 
00246         if(minorVersion)
00247             *minorVersion = V_UI1(&pVal); 
00248     }
00249 
00250     static void GetWMISMBIOSData( WMISMBIOSINFO &smbiosData )
00251     {
00252         IWbemClassObject    *pSmbios = NULL;
00253 
00254         try
00255         {
00256             if (! SUCCEEDED( CoInitialize(0) ) )
00257                 throw InternalErrorImpl( _("Could not initialize COM.") );
00258 
00259             GetWMISMBIOSEntry( &pSmbios );
00260             GetWMISMBIOSTable( pSmbios, smbiosData );
00261             GetWMISMBIOSVersion( pSmbios, &smbiosData.majorVersion, &smbiosData.minorVersion );
00262         }
00263         catch(const exception &)
00264         {
00265             delete [] smbiosData.buffer;
00266             smbiosData.buffer = 0;
00267             throw;
00268         }
00269         CoUninitialize();
00270     }
00271 
00272 
00273     bool SmbiosWinWMIStrategy::getSmbiosTable(const u8 **smbiosBuffer, smbiosLowlevel::smbios_table_entry_point *table_header, bool )
00274     {
00275         // new throws exception, no need to test.
00276         WMISMBIOSINFO wmi_smbiosData;
00277         memset(&wmi_smbiosData, 0, sizeof(wmi_smbiosData));
00278 
00279         GetWMISMBIOSData( wmi_smbiosData );
00280 
00281         if( wmi_smbiosData.bufferSize <= 0 || ! wmi_smbiosData.buffer )
00282             throw ParseExceptionImpl( _("getSmbiosTable(): GetWMISMBIOSData returned 0 for buffer size.") );
00283 
00284         // fake version information for now.
00285         table_header->table_length = static_cast<u16>(wmi_smbiosData.bufferSize);
00286         table_header->major_ver = wmi_smbiosData.majorVersion;
00287         table_header->minor_ver = wmi_smbiosData.minorVersion;
00288         table_header->table_num_structs = 9999;
00289 
00290         //delete old one, if necessary
00291         if( *smbiosBuffer )
00292         {
00293             memset (const_cast<u8 *>(*smbiosBuffer), 0, sizeof (**smbiosBuffer));
00294             delete [] const_cast<u8 *>(*smbiosBuffer);
00295             *smbiosBuffer = 0;
00296         }
00297 
00298         *smbiosBuffer = (const u8 *) wmi_smbiosData.buffer;
00299         return true;
00300     }
00301 #else
00302     bool SmbiosWinWMIStrategy::getSmbiosTable(const u8 **, smbiosLowlevel::smbios_table_entry_point *, bool )
00303     {
00304         return false;
00305     }
00306 #endif /* LIBSMBIOS_WIN_USE_WMI */
00307 }
00308 

Generated on Tue Jan 17 02:59:08 2006 for SMBIOS Library by  doxygen 1.4.6