2009-09-16 13 views
6

Tengo una aplicación C pura que emite llamadas IOCTL a mi controlador de adaptador y muestra información, esto sin embargo se compila con Visual Developer Studio 5 (código no administrado) ... Sin embargo, necesito obtener información de mi adaptador usando WMI .... Mis esfuerzos en Google muestran que necesitaría escribir una Aplicación C++ usando COM para lograr cualquier forma de comunicación con wMI o C# con la aplicación .NET a) ¿Es así realmente? NO hay problema para mi aplicación C? b) Si lo anterior es cierto, ¿cuáles son los cambios de nivel mínimo que necesitaría para realizar mis configuraciones de proyecto/wp/workspace?¿Cómo obtener datos de WMI usando una aplicación C?

Gracias Som

Respuesta

13

puede invocar COM de C. La sintaxis es un poco menos agradable que la de C++, pero funciona. COM se diseñó inicialmente para funcionar desde C o C++, y el soporte nativo de lenguaje C se incluye en los archivos de encabezado COM y WMI. Sin embargo, será largo ... su programa será responsable de asignar todos los objetos necesarios, verificar las condiciones de error de todas y cada una de las llamadas COM y liberar los objetos que creó.

Al utilizar la documentación escrita con C++ en mente, convertir llamadas COM de la forma:

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

a:

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

A continuación se muestra la pieza más corta del código C que pudiera llegar a realidad tirar algo de información de WMI. Si tiene éxito, debe enumerar los procesadores en su computadora, junto con su frecuencia de reloj en MHz. El programa se encarga de eliminar los recursos que asigna, pero no realiza ningún tipo de comprobación de errores (debe mirar esos valores hr antes de continuar con cada paso).

Esto es un estudio visual 2008 "Aplicación de consola Win32" con el archivo principal renombrado a una extensión .c, y los archivos extra stdafx eliminados. Para que el programa se vincule, asegúrese de incluir wbemuuid.lib en las propiedades del proyecto, en Propiedades de configuración/Enlazador/Entrada/Dependencias adicionales. Funcionó con éxito en mi caja 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

Hola Oren, Gracias por tonelada, que funcionó como un campeón en Win2008 .Sin embargo, me encontré con problemas de compilación La primera vez que probé en Visual Studio 2005, poniéndolos a continuación: error C2065: 'COINIT_MULTITHREADED': identificador no declarado error C2065: 'EOAC_NONE': identificador no declarado ¿Alguna idea sobre cómo resolverlos para 2005? Gracias Som – smam

+0

Pruebe agregar #define _WIN32_WINNT 0x0400 y #define _WIN32_DCOM antes de incluir archivos. Si eso no resuelve el problema, simplemente reemplace las dos constantes que faltan por 0. –

+0

Hola Oren, Sí, funcionó con la primera libra se define a sí misma, una vez más muchas gracias Som – smam

2

Otra opción, si desea mantener el impacto de su aplicación existente C bajo, es escribir un archivo DLL que internamente puede utilizar C++ y las clases COM envoltura para consultar la información de WMI deseada.

Esta DLL puede proporcionar una interfaz C simple para adaptarse a su aplicación. Esa es la forma en que iría.

+1

Absolutamente, manejar todas las cosas COM en C no solo es un dolor, sino también en un nivel de abstracción completamente diferente en comparación con la aplicación real. – Wolf

Cuestiones relacionadas