WMI
WMI est une API créée en 1998 par Microsoft qui permet de gèrer une base de données sur chaque PC sur lequel il est installé contenant des informations liées aux matériels et logiciels installés sur votre ordinateur. WMI permet aussi d'obtenir des informations sur un ordinateur distant mais je ne développerais pas ce sujet car je ne sais pas comment faire .... pour le moment. (Noob Inside)
Des classes
Chaque information logiciel/matériel est regroupée à travers des classes.
Exemple de quelques classes : Win32_MotherboardDevice, Win32_NetworkAdapterConfiguration, Win32_DisplayConfiguration, etc...
Des propriétes
Une classe contient des propriétés
Exemple d'une classe contenant un extrait des propriétés.
class Win32_ComputerSystem
string Manufacturer;
string Model;
string SystemType;
Une requête
Connaitre des informations sur une classe consiste à exécuter une requête de type WQL. ça ressemble à des requêtes SQL en moins bien.
Exemples de requête:
Select * from Win32_ComputerSystem Pour sélectionner toutes les propriétes d'une classe.
Select Manufacturer, Model, SystemType from Win32_ComputerSystem pour sélectionner quelques propriétés.
Mise en oeuvre avec Pure Basic
J'ai repris un code sur lequel plusieurs utilisateurs de Pure Basic se sont pencher pour en sortir quelques chose de fonctionnelle. J'ai juste modifier ce code en ajoutant une liste structurée qui contient le résultat des requêtes.
Pour ce premier tutoriel, je veux connaitre le fabriquant, le model et le type de système qui fonctionne sur l'ordinateur de mon ordinateur.
Pour cela je veux interroger la classe Win32_ComputerSystem
Vous devez inclure le fichier WMIQuery.pbi
Code : Tout sélectionner
IncludeFile "WMIQuery.pbi"
Cette structure contient les variable Property (string) et Value (String)
Dans votre code, il est nécessaire de sérialiser cette structure.
Code : Tout sélectionner
NewList WMIResult.WMIClass()
WMIQuery(WMIReqSql.s, Liste())
WMIReqSql : La requête que vous envoyer.
Liste() : La liste structurée que vous avez défini.
Code : Tout sélectionner
WMIQuery("Select Manufacturer, Model, SystemType from Win32_ComputerSystem", WMIResult())
Code : Tout sélectionner
ForEach WMIResult()
Debug WMIResult()\Property + "=" + WMIResult()\Value
Next
Code : Tout sélectionner
;Computer Manufacturer
IncludeFile "WMIQuery.pbi"
NewList WMIResult.WMIClass()
If WMIQuery("Select Manufacturer, Model, SystemType from Win32_ComputerSystem", WMIResult())
ForEach WMIResult()
Debug WMIResult()\Property + "=" + WMIResult()\Value
Next
EndIf
Code : Tout sélectionner
;WMIQuery Version 1.00
;
;Pure Basic 4.51, 4.61, 5.00 Beta
;
;Contributor : Andre (2004), DataMiner (2005) ..... others who have tried :)
;Update : falsam (19.09.2012)
;
;Add
;Procedure WMIQuery(WMIReqSql.s, Map WMIMap.s())
;Run a WMI query and retrieve one or all properties of a class in a map
;
;Example
;NewList WMIResult.WMIClass()
;If WMIQuery("Select Manufacturer, Model, SystemType from Win32_ComputerSystem", WMIResult())
; ForEach WMIResult()
; Debug WMIResult()\Property + "=" + WMIResult()\Value
; Next
;EndIf
;WMI constants
#RPC_C_AUTHN_LEVEL_CONNECT = 2
#RPC_C_IMP_LEVEL_IDENTIFY = 2
#EOAC_NONE = 0
#RPC_C_AUTHN_WINNT = 10
#RPC_C_AUTHZ_NONE = 0
#RPC_C_AUTHN_LEVEL_CALL = 3
#RPC_C_IMP_LEVEL_IMPERSONATE = 3
#CLSCTX_INPROC_SERVER = 1
#WBEMFlagReturnImmediately = 16
#wbemFlagForwardOnly = 32
#WBEM_INFINITE = $FFFFFFFF
#IFlags = #wbemFlagReturnImmediately + #wbemFlagForwardOnly
Structure WMIClass
Property.s
Value.s
EndStructure
Procedure.l ansi2bstr(ansi.s)
Protected Size.l, i.i, tmp.s
size=MultiByteToWideChar_(#CP_ACP,0,ansi,Len(ansi),0,0)
Dim unicode.w(size)
MultiByteToWideChar_(#CP_ACP, 0, ansi, Len(ansi), unicode(), size);#CP_ACP
For i=0 To size
tmp + Hex(unicode(i),#PB_Unicode)
Next
ProcedureReturn SysAllocString_(@unicode())
EndProcedure
Procedure bstr2string (bstr)
Static result.s
result = PeekS(bstr, -1, #PB_Unicode)
ProcedureReturn @result
EndProcedure
; Interrogate WMI Database
Procedure WMIQuery(WMIReqSql.s, List WMI.WMIClass())
Protected Mem.l
Protected hres.i
Protected loc.IWbemLocator
Protected svc.IWbemServices
Protected pUnk.IUnknown
Protected pEnumerator.IEnumWbemClassObject
Protected pclsObj.IWbemClassObject
Protected uReturn
Protected sf.l
Protected lBound.i, uBound.i, i.i
Protected temp.l, x.Variant, Type.i
Protected Property.s, Val.s
Protected nDim.i, plUbound.i, z.i, rgVar
ClearList(WMI())
; --- Step 1: Initialize COM parameters with a call to CoInitializeEx
CoInitializeEx_(0, #COINIT_MULTITHREADED)
; --- Step 2: Initialize COM process security by calling CoInitializeSecurity.
hres=CoInitializeSecurity_(0, -1,0,0,#RPC_C_AUTHN_LEVEL_CONNECT,#RPC_C_IMP_LEVEL_IDENTIFY,0,#EOAC_NONE,0)
If hres <> 0
MessageRequester("ERROR", "unable to call CoInitializeSecurity", #MB_OK)
CoUninitialize_()
ProcedureReturn #False
EndIf
; --- Step 3: Obtain the initial locator to WMI by calling CoCreateInstance.
hres=CoCreateInstance_(?CLSID_WbemLocator,0,#CLSCTX_INPROC_SERVER,?IID_IWbemLocator,@loc.IWbemLocator)
If hres <> 0
MessageRequester("ERROR", "unable to call CoCreateInstance", #MB_OK)
loc\release()
CoUninitialize_()
ProcedureReturn #False
EndIf
; --- Step 4: Obtain a pointer to IWbemServices for the root\cimv2 namespace on the local computer by calling IWbemLocator::ConnectServer.
;hres=loc\ConnectServer(Ansi2Uni("root\cimv2"),0,0,0,0,0,0,@svc)
If #PB_Compiler_Unicode = 1;we create unicode application
hres=loc\ConnectServer(@"root\cimv2" ,0,0,0,0,0,0,@svc.IWbemServices)
Else; non unicode
hres=loc\ConnectServer(ansi2bstr("root\cimv2"),0,0,0,0,0,0,@svc.IWbemServices)
EndIf
If hres <> 0
MessageRequester("ERROR", "unable to call IWbemLocator::ConnectServer", #MB_OK)
svc\release()
loc\release()
CoUninitialize_()
ProcedureReturn #False
EndIf
; --- Step 5: Set IWbemServices proxy security so the WMI service can impersonate the client by calling CoSetProxyBlanket.
hres=svc\queryinterface(?IID_IUnknown,@pUnk.IUnknown)
hres=CoSetProxyBlanket_(svc,#RPC_C_AUTHN_WINNT,#RPC_C_AUTHZ_NONE,0,#RPC_C_AUTHN_LEVEL_CALL,#RPC_C_IMP_LEVEL_IMPERSONATE,0,#EOAC_NONE)
If hres <> 0
MessageRequester("ERROR", "unable to call CoSetProxyBlanket", #MB_OK)
svc\release()
loc\release()
CoUninitialize_()
ProcedureReturn #False
EndIf
hres=CoSetProxyBlanket_(pUnk,#RPC_C_AUTHN_WINNT,#RPC_C_AUTHZ_NONE,0,#RPC_C_AUTHN_LEVEL_CALL,#RPC_C_IMP_LEVEL_IMPERSONATE,0,#EOAC_NONE)
If hres <> 0
MessageRequester("ERROR", "unable to call CoSetProxyBlanket", #MB_OK)
svc\release()
loc\release()
CoUninitialize_()
ProcedureReturn #False
EndIf
pUnk\release()
; --- Step 6: Use the IWbemServices pointer to make requests of WMI.
;hres=svc\ExecQuery(Ansi2Uni("WQL"), Ansi2Uni(WMIReqSql), #IFlags,0,@pEnumerator)
;hres=svc\ExecQuery(@"WQL",@WMIobj, #IFlags,0,@pEnumerator.IEnumWbemClassObject)
If #PB_Compiler_Unicode = 1
hres=svc\ExecQuery(@"WQL",@WMIReqSql, #IFlags,0,@pEnumerator.IEnumWbemClassObject)
Else
hres=svc\ExecQuery(ansi2bstr("WQL"),ansi2bstr(WMIReqSql), #IFlags,0,@pEnumerator.IEnumWbemClassObject)
EndIf
If hres <> 0
MessageRequester("ERROR", "unable to call IWbemServices::ExecQuery", #MB_OK)
svc\Release()
loc\Release()
pEnumerator\Release()
CoUninitialize_()
ProcedureReturn #False
EndIf
; --- Step 7: Get the data from the WQL query. The IEnumWbemClassObject pointer is linked to the data objects that the query returned,
; --- and the data objects can be retrieved with the IEnumWbemClassObject::Next method. This method links the data objects to an IWbemClassObject pointer
; --- that is passed into the method. Use the IWbemClassObject::Get method to get the desired information from the data objects.
mem=AllocateMemory(1000)
hres=pEnumerator\reset()
Repeat
hres = pEnumerator\Next(#WBEM_INFINITE, 1, @pclsObj.IWbemClassObject, @uReturn)
If uReturn = 0
Break
EndIf
; get a list with the names of the properties.
hres=pclsObj\GetNames(0, 0, 0,@sf.l); get a list with the names of the properties.
SafeArrayGetLBound_(sf, 1, @lBound)
SafeArrayGetUBound_(sf, 1, @uBound)
Dim indices(1)
For i = lbound To ubound
indices(0) = i
SafeArrayGetElement_(sf, @indices(), @temp)
If temp
Property = PeekS(temp, -1, #PB_Unicode)
If #PB_Compiler_Unicode = 1
hres=pclsObj\get(@Property, 0, mem, 0, 0)
Else
hres=pclsObj\get(ansi2bstr(Property), 0, mem, 0, 0)
EndIf
type=PeekW(mem)
Select type
Case 8
val.s=PeekS(bstr2string(PeekL(mem+8)))
Case 3
val.s=Str(PeekL(mem+8))
Default
val.s=""
EndSelect
If FindString(WMIReqSql,"*",1) <> 0;we need everything, not just some specific properties
AddElement(WMI())
WMI()\Property = Property
WMI()\Value = val
ElseIf Left(Property,1)<>"_";we need some specific properties, not all, not these starting with '_'.
AddElement(WMI())
WMI()\Property = Property
WMI()\Value = val
EndIf
EndIf
Next
Until uReturn = 0
; --- Step 8: Cleanup
svc\release()
loc\release()
pEnumerator\release()
If uReturn
pclsObj\release()
EndIf
CoUninitialize_()
ProcedureReturn #True
EndProcedure
;- Data Section
DataSection
CLSID_IEnumWbemClassObject:
;1B1CAD8C-2DAB-11D2-B604-00104B703EFD
Data.l $1B1CAD8C
Data.w $2DAB, $11D2
Data.b $B6, $04, $00, $10, $4B, $70, $3E, $FD
IID_IEnumWbemClassObject:
;7C857801-7381-11CF-884D-00AA004B2E24
Data.l $7C857801
Data.w $7381, $11CF
Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24
CLSID_WbemLocator:
;4590f811-1d3a-11d0-891f-00aa004b2e24
Data.l $4590F811
Data.w $1D3A, $11D0
Data.b $89, $1F, $00, $AA, $00, $4B, $2E, $24
IID_IWbemLocator:
;dc12a687-737f-11cf-884d-00aa004b2e24
Data.l $DC12A687
Data.w $737F, $11CF
Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24
IID_IUnknown:
;00000000-0000-0000-C000-000000000046
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection


la liste des classes sur ce lien (En anglais). En français sur cet autre site mais je pense qu'il est incomplet.