2009-09-16 3 views
6

J'ai une application C pure qui émet des appels IOCTL vers mon pilote de carte et affiche des informations, mais compilées avec Visual Developer Studio 5 (code non géré) ... J'ai besoin d'informations sur mon adaptateur en utilisant WMI .... Mes efforts googling montrent que je devrais écrire une application C++ en utilisant COM pour réaliser toute forme de communication avec wMI ou un C# avec l'application .NET a) Est-ce vraiment le cas? Pas de travail autour de mon application C? b) Si ce qui précède est vrai, quels sont les changements de niveau minimum dont j'aurais besoin pour effectuer mes réglages projet/wp/espace de travail?Comment obtenir des données de WMI en utilisant une application C?

Merci Som

Répondre

13

Vous pouvez appeler COM de C. La syntaxe est un peu moins convivial que celui de C++, mais il fonctionne. COM a été initialement conçu pour fonctionner à partir de C ou C++, et le support du langage C natif est inclus dans les fichiers d'en-tête COM et WMI. Ce sera long cependant ... votre programme sera chargé d'allouer tous les objets nécessaires, de vérifier les conditions d'erreur de chaque appel COM, et de libérer les objets instanciés.

Lors de l'utilisation des documents écrits en C++ à l'esprit, convertir les appels COM du formulaire:

pSomething->Method(arg1, ...); // C++ 

à:

pSomething->lpVtbl->Method(pSomething, arg1, ...); // C 

est inférieure à la plus courte morceau de code C je pourrais arriver à réellement tirer quelques informations de WMI. En cas de succès, il devrait répertorier les processeurs sur votre ordinateur, avec leur fréquence d'horloge en MHz. Le programme prend soin de disposer des ressources qu'il alloue, mais il ne vérifie absolument pas les erreurs (vous devriez regarder ces valeurs avant de continuer chaque étape).

Il s'agit d'une application "console Win32 2008" de Visual Studio avec le fichier principal renommé en extension .c et les fichiers stdafx supplémentaires supprimés. Pour que le programme soit lié, assurez-vous d'inclure wbemuuid.lib dans les propriétés du projet, sous Propriétés de configuration/Lieur/Entrée/Dépendances supplémentaires. Il a fonctionné avec succès sur ma boîte de Vista.

#define _WIN32_WINNT 0x0400 
#define _WIN32_DCOM 

#include <stdio.h> 
#include <tchar.h> 
#include <windows.h> 
#include <wbemidl.h> 

void _tmain(int argc, _TCHAR* argv[]) 
{ 
    // result code from COM calls 
    HRESULT hr = 0; 

    // COM interface pointers 
    IWbemLocator   *locator = NULL; 
    IWbemServices  *services = NULL; 
    IEnumWbemClassObject *results = NULL; 

    // BSTR strings we'll use (http://msdn.microsoft.com/en-us/library/ms221069.aspx) 
    BSTR resource = SysAllocString(L"ROOT\\CIMV2"); 
    BSTR language = SysAllocString(L"WQL"); 
    BSTR query = SysAllocString(L"SELECT * FROM Win32_Processor"); 

    // initialize COM 
    hr = CoInitializeEx(0, COINIT_MULTITHREADED); 
    hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); 

    // connect to WMI 
    hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *) &locator); 
    hr = locator->lpVtbl->ConnectServer(locator, resource, NULL, NULL, NULL, 0, NULL, NULL, &services); 

    // issue a WMI query 
    hr = services->lpVtbl->ExecQuery(services, language, query, WBEM_FLAG_BIDIRECTIONAL, NULL, &results); 

    // list the query results 
    if (results != NULL) { 
     IWbemClassObject *result = NULL; 
     ULONG returnedCount = 0; 

     // enumerate the retrieved objects 
     while((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) { 
      VARIANT name; 
      VARIANT speed; 

      // obtain the desired properties of the next result and print them out 
      hr = result->lpVtbl->Get(result, L"Name", 0, &name, 0, 0); 
      hr = result->lpVtbl->Get(result, L"MaxClockSpeed", 0, &speed, 0, 0); 
      wprintf(L"%s, %dMHz\r\n", name.bstrVal, speed.intVal); 

      // release the current result object 
      result->lpVtbl->Release(result); 
     } 
    } 

    // release WMI COM interfaces 
    results->lpVtbl->Release(results); 
    services->lpVtbl->Release(services); 
    locator->lpVtbl->Release(locator); 

    // unwind everything else we've allocated 
    CoUninitialize(); 

    SysFreeString(query); 
    SysFreeString(language); 
    SysFreeString(resource); 
} 
+0

Salut Oren, Merci une tonne, qui a travaillé comme un champion sur Win2008 .Cependant, je suis tombé sur des problèmes de compilation quand j'ai essayé sur Visual Studio 2005, les mettre ci-après: erreur C2065: « COINIT_MULTITHREADED »: identificateur non déclaré erreur C2065: 'EOAC_NONE': identificateur non déclaré Une idée sur la façon de les résoudre pour 2005? Merci Som – smam

+0

Essayez d'ajouter #define _WIN32_WINNT 0x0400 et #define _WIN32_DCOM avant les fichiers d'inclusion. Si cela ne résout pas le problème, il suffit de remplacer les deux constantes manquantes par 0. –

+0

Hi Oren, Oui, il a travaillé avec la première livre se définir, encore une fois merci beaucoup Som – smam

2

Une autre option, si vous voulez garder l'impact sur votre application C existante faible, est d'écrire une DLL qui peut utiliser en interne les classes wrapper C++ et COM pour interroger les informations WMI souhaité.

Cette DLL peut fournir une interface C simple à adapter à votre application. C'est comme ça que j'irais.

+1

Absolument, en manipulant tous les trucs COM en C non seulement une douleur, mais aussi un niveau d'abstraction complètement différent par rapport à l'application réelle. – Wolf

Questions connexes