2009-09-16 12 views
6

Ho un'applicazione C pura che emette chiamate IOCTL al mio driver dell'adattatore e visualizza informazioni, tuttavia è compilato utilizzando Visual Developer Studio 5 (codice non gestito) ... Ho bisogno di ottenere comunque alcune informazioni dal mio adattatore usando WMI .... I miei sforzi googling dimostrano che avrei bisogno di scrivere un'applicazione C++ usando COM per ottenere qualsiasi forma di comunicazione con wMI o C# con l'app .NET a) È proprio così? Niente da fare per la mia applicazione C? b) Se sopra è vero, quali sono le modifiche di livello minimo che avrei bisogno di fare le mie impostazioni di project/wp/workspace?Come ottenere dati da WMI utilizzando un'applicazione C?

Grazie Som

risposta

13

È possibile richiamare COM da C. La sintassi è un po 'meno accogliente di quella di C++, ma funziona. COM è stato inizialmente progettato per funzionare da C o C++ e il supporto del linguaggio C nativo è incluso nei file di intestazione COM e WMI. Sarà lungo però ... il tuo programma sarà responsabile per l'assegnazione di tutti gli oggetti necessari, il controllo delle condizioni di errore da ogni chiamata COM e per il rilascio degli oggetti che ha istanziato.

Quando si utilizza la documentazione scritta in C++ in mente, convertire le chiamate COM della forma:

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

a:

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

Di seguito si riporta il pezzo più breve di codice C ho potuto ottenere in realtà tirare alcune informazioni da WMI. Se ha successo, dovrebbe elencare i processori sul tuo computer, insieme alla loro frequenza di clock in MHz. Il programma si occupa di smaltire le risorse allocate, ma non esegue alcun controllo di errore (è necessario esaminare i valori di hr prima di continuare ogni passaggio).

Questa è un'applicazione di Visual Studio 2008 "Applicazione console Win32" con il file principale rinominato in estensione .c e i file extra stdafx rimossi. Per ottenere il collegamento al programma, assicurarsi di includere wbemuuid.lib nelle proprietà del progetto, in Proprietà di configurazione/Linker/Input/Dipendenze aggiuntive. Ha funzionato con successo sul mio box 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

Hi Oren, Grazie una tonnellata, che ha funzionato come un campione su Win2008 .Tuttavia, mi sono imbattuto in problemi di compilazione Quando ho provato su Visual Studio 2005, mettendoli qui di seguito: Errore C2065: 'COINIT_MULTITHREADED': identificatore non dichiarato errore C2065: 'EOAC_NONE': identificatore non dichiarato Qualche idea su come risolverli per il 2005? Grazie Som – smam

+0

Prova ad aggiungere #define _WIN32_WINNT 0x0400 e #define _WIN32_DCOM prima dei file di inclusione. Se questo non risolve il problema, sostituisci entrambe le costanti mancanti con 0. –

+0

Ciao Oren, Sì, ha funzionato con la prima libbra, si definisce ancora una volta grazie mille Som – smam

2

Un'altra opzione, se si vuole mantenere l'impatto alla vostra applicazione C esistente basso, è quello di scrivere una DLL che internamente può usare C++ e le classi wrapper COM per interrogare le informazioni WMI desiderato.

Questa DLL può fornire un'interfaccia C semplice per adattarsi all'applicazione. Questo è il modo in cui vorrei andare.

+1

Assolutamente, la gestione di tutti gli elementi COM in C non è solo un dolore, ma anche un livello di astrazione completamente diverso rispetto all'applicazione reale. – Wolf