【问题标题】:How to obtain data from WMI using a C Application?如何使用 C 应用程序从 WMI 获取数据?
【发布时间】:2010-11-28 16:50:33
【问题描述】:

我有一个纯 C 应用程序,它向我的适配器驱动程序发出 IOCTL 调用并显示信息,但是这是使用 Visual Developer Studio 5(非托管代码)编译的......但是我需要使用我的适配器从我的适配器获取一些信息WMI .... 我的谷歌搜索表明我需要使用 COM 编写一个 C++ 应用程序来实现与 wMI 的任何形式的通信或与 .NET 应用程序的 C# a) 真的是这样吗?我的 C 应用程序没有解决方法? b) 如果上述情况属实,我需要进行项目/wp/工作区设置的最低级别更改是什么?

谢谢 索姆

【问题讨论】:

    标签: c wmi


    【解决方案1】:

    您可以从 C 中调用 COM。语法不如 C++ 友好,但它可以工作。 COM 最初设计为使用 C 或 C++ 工作,并且本机 C 语言支持包含在 COM 和 WMI 头文件中。不过会很长...您的程序将负责分配所有必要的对象,检查每个 COM 调用的错误情况,并释放它实例化的对象。

    在使用以 C++ 编写的文档时,转换以下形式的 COM 调用:

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

    到:

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

    下面是最短的一段 C 代码,我可以从 WMI 中实际提取一些信息。如果成功,它应该列出您计算机上的处理器,以及它们的时钟频率(以 MHz 为单位)。该程序负责处理它分配的资源,但它不进行任何错误检查(在继续每个步骤之前,您应该查看这些 hr 值)。

    这是一个 Visual Studio 2008“Win32 控制台应用程序”,主文件重命名为 .c 扩展名,并删除了额外的 stdafx 文件。要使程序链接,请确保在项目属性中包含 wbemuuid.lib,在 Configuration Properties/Linker/Input/Additional Dependencies 下。它在我的 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);
    }
    

    【讨论】:

    • 嗨 Oren,非常感谢,它在 Win2008 上的工作就像一个冠军。但是,当我第一次在 Visual Studio 2005 上尝试它时遇到了编译问题,将它们放在下面:错误 C2065:'COINIT_MULTITHREADED ' : undeclared identifier error C2065: 'EOAC_NONE' : undeclared identifier 关于如何在 2005 年解决它们的任何想法?谢谢索姆
    • 尝试在包含文件之前添加#define _WIN32_WINNT 0x0400 和#define _WIN32_DCOM。如果这不能解决问题,只需将两个缺失的常量都替换为 0。
    • 嗨 Oren,是的,它与第一磅定义本身一起工作,再次非常感谢 Som
    • 很高兴知道所有细节,但知道有options to forget about them 可能更好:-)
    【解决方案2】:

    另一个选项,如果您想保持对现有 C 应用程序的影响较低,是编写一个内部可以使用 C++ 和 COM 包装类来查询所需 WMI 信息的 DLL。

    这个 DLL 可以提供一个纯 C 接口来适应您的应用程序。这就是我想要的方式。

    【讨论】:

    • 当然,在 C 中处理所有 COM 内容不仅很痛苦,而且与实际应用程序相比,抽象级别也完全不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 2014-09-08
    • 2015-06-27
    • 1970-01-01
    • 2021-07-18
    相关资源
    最近更新 更多