当前位置:首页 > c++ > 正文内容

使用wmi获取电脑信息(bios序列号、磁盘序列号、cpu序列号、主板序列号、网卡序列号等)

xuwenyan10个月前 (02-06)c++869

wmi_api.h

#ifndef WMI_API_H_
#define WMI_API_H_

#include <string>
#include <wbemidl.h>
#include <wrl/client.h>

// Enumeration of errors that can arise when connecting to a WMI server and
// running a query.
// Do not change ordering. This enum is captured as `WmiQueryError` in
// enums.xml.
enum class WmiError
{
    kNoError = 0,
    kFailedToCreateInstance,
    kFailedToConnectToWMI,
    kFailedToSetSecurityBlanket,
    kFailedToExecWMIQuery,
    kMaxValue = kFailedToExecWMIQuery
};

// String used to connect to the CIMV2 WMI server.
extern const wchar_t kCimV2ServerName[];

// String used to connect to the SecurityCenter2 WMI server.
extern const wchar_t kSecurityCenter2ServerName[];

// Connects to a server named `server_name` on the local computer through COM
// and run the given WQL `query`. Sets `enumerator` with the values returned by
// that `query`. Will return a WmiError value if an error occurs, else returns
// absl::nullopt.
WmiError RunWmiQuery(
    const std::wstring& server_name,
    const std::wstring& query,
    Microsoft::WRL::ComPtr<IEnumWbemClassObject>* enumerator);

// Creates an instance of the WMI service connected to the local computer and
// returns its COM interface. If |set_blanket| is set to true, the basic COM
// security blanket is applied to the returned interface. This is almost
// always desirable unless you set the parameter to false and apply a custom
// COM security blanket.
// Returns true if succeeded and |wmi_services|: the pointer to the service.
bool CreateLocalWmiConnection(
    bool set_blanket,
    Microsoft::WRL::ComPtr<IWbemServices>* wmi_services);

// Creates a WMI method using from a WMI class named |class_name| that
// contains a method named |method_name|. Only WMI classes that are CIM
// classes can be created using this function.
// Returns true if succeeded and |class_instance| returns a pointer to the
// WMI method that you can fill with parameter values using SetParameter.
bool CreateWmiClassMethodObject(
    IWbemServices* wmi_services,
    std::wstring class_name,
    std::wstring method_name,
    Microsoft::WRL::ComPtr<IWbemClassObject>* class_instance);

// Creates a new process from |command_line|. The advantage over CreateProcess
// is that it allows you to always break out from a Job object that the caller
// is attached to even if the Job object flags prevent that.
// Returns true and the process id in process_id if the process is launched
// successful. False otherwise.
// Note that a fully qualified path must be specified in most cases unless
// the program is not in the search path of winmgmt.exe.
// Processes created this way are children of wmiprvse.exe and run with the
// caller credentials.
// More info: http://msdn2.microsoft.com/en-us/library/aa394372(VS.85).aspx
bool WmiLaunchProcess(const std::wstring& command_line,
    int* process_id);

// An encapsulation of information retrieved from the 'Win32_ComputerSystem' and
// 'Win32_Bios' WMI classes; see :
// https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-computersystem
// https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-systembios
// Note that while model and manufacturer can be obtained through WMI, it is
// more efficient to obtain them via SysInfo::GetHardwareInfo() which uses the
// registry.
class WmiComputerSerialNumber
{
public:
    typedef struct
    {
        std::wstring id;
        std::wstring sql;
        std::wstring key;

    }INFO;

    INFO query_arr[7] =
    {
        {L"hd",L"SELECT * FROM Win32_DiskDrive WHERE (SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed hard disk%')",L"SerialNumber"},// 硬盘序列号
        {L"hdn",L"SELECT * FROM Win32_PhysicalMedia WHERE (SerialNumber IS NOT NULL)",L"SerialNumber"},// 硬盘序列号 
        {L"board_sn",L"SELECT * FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)",L"SerialNumber"},// 主板序列号 
        {L"board_type",L"SELECT * FROM Win32_BaseBoard WHERE (Product IS NOT NULL)",L"Product"},// 主板型号
        {L"cpu",L"SELECT * FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)",L"ProcessorId"},// 处理器ID  
        {L"bios",L"SELECT * FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)",L"SerialNumber"},// BIOS序列号
        {L"mac",L"SELECT * FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))",L"MACAddress"}// 网卡当前MAC地址 
    };

    std::wstring Bios();
    std::wstring DiskDrive();
    std::wstring Get(const std::wstring& id);

private:
    void PopulateValue(
        const Microsoft::WRL::ComPtr<IEnumWbemClassObject>& enumerator_bios,
        const std::wstring& key,
        std::wstring* output);
};

#endif  // WMI_API_H_

wmi_api.cpp

// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "wmi_api.h"

#include <windows.h>

#include <objbase.h>
#include <stdint.h>
#include <utility>

#pragma comment(lib, "wbemuuid.lib")

using Microsoft::WRL::ComPtr;

const wchar_t kCimV2ServerName[] = L"ROOT\\CIMV2";

const wchar_t kSecurityCenter2ServerName[] = L"ROOT\\SecurityCenter2";

namespace
{
    void TerminateBecauseOutOfMemory(size_t size)
    {
        const DWORD kOomExceptionCode = 0xe0000008;
        ULONG_PTR exception_args[] = { size };
        ::RaiseException(kOomExceptionCode, EXCEPTION_NONCONTINUABLE,
            std::size(exception_args), exception_args);

        // Safety check, make sure process exits here.
        _exit(kOomExceptionCode);
    }

    BSTR AllocBstrOrDie(std::wstring non_bstr)
    {
        BSTR result = ::SysAllocStringLen(non_bstr.data(),
            static_cast<UINT>(non_bstr.length()));
        if (!result)
            TerminateBecauseOutOfMemory((non_bstr.length() + 1) *
                sizeof(wchar_t));
        return result;
    }

    BSTR AllocBstrBytesOrDie(size_t bytes)
    {
        BSTR result = ::SysAllocStringByteLen(nullptr, static_cast<UINT>(bytes));
        if (!result)
            TerminateBecauseOutOfMemory(bytes + sizeof(wchar_t));
        return result;
    }


    // Manages a BSTR string pointer.
    // The class interface is based on unique_ptr.
    class ScopedBstr
    {
    public:
        ScopedBstr(std::wstring non_bstr)
            : bstr_(AllocBstrOrDie(non_bstr))
        {
        }

        ScopedBstr(const ScopedBstr&) = delete;
        ScopedBstr& operator=(const ScopedBstr&) = delete;

        ~ScopedBstr()
        {
            static_assert(sizeof(ScopedBstr) == sizeof(BSTR), "ScopedBstrSize");
            ::SysFreeString(bstr_);
        }

        BSTR Get() const { return bstr_; }

        // Give ScopedBstr ownership over an already allocated BSTR or null.
        // If you need to allocate a new BSTR instance, use |allocate| instead.
        void Reset(BSTR bstr)
        {
            if (bstr != bstr_)
            {
                // SysFreeString handles null properly.
                ::SysFreeString(bstr_);
                bstr_ = bstr;
            }
        }

        // Releases ownership of the BSTR to the caller.
        BSTR Release()
        {
            BSTR bstr = bstr_;
            bstr_ = nullptr;
            return bstr;
        }

        // Swap values of two ScopedBstr's.
        void Swap(ScopedBstr& bstr2)
        {
            BSTR tmp = bstr_;
            bstr_ = bstr2.bstr_;
            bstr2.bstr_ = tmp;
        }

        // Retrieves the pointer address.
          // Used to receive BSTRs as out arguments (and take ownership).
          // The function DCHECKs on the current value being null.
          // Usage: GetBstr(bstr.Receive());
        BSTR* Receive()
        {
            return &bstr_;
        }

        // Creates a new BSTR from a 16-bit C-style string.
         //
         // If you already have a BSTR and want to transfer ownership to the
         // ScopedBstr instance, call |reset| instead.
         //
         // Returns a pointer to the new BSTR.
        BSTR Allocate(std::wstring str)
        {
            Reset(AllocBstrOrDie(str));
            return bstr_;
        }

        // Allocates a new BSTR with the specified number of bytes.
       // Returns a pointer to the new BSTR.
        BSTR AllocateBytes(size_t bytes)
        {
            Reset(AllocBstrBytesOrDie(bytes));
            return bstr_;
        }

        // Sets the allocated length field of the already-allocated BSTR to be
      // |bytes|.  This is useful when the BSTR was preallocated with e.g.
      // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and then
      // not all the bytes are being used.
      //
      // Note that if you want to set the length to a specific number of
      // characters, you need to multiply by sizeof(wchar_t).  Oddly, there's no
      // public API to set the length, so we do this ourselves by hand.
      //
      // NOTE: The actual allocated size of the BSTR MUST be >= bytes.  That
      // responsibility is with the caller.
        void SetByteLen(size_t bytes)
        {
            uint32_t* data = reinterpret_cast<uint32_t*>(bstr_);
            data[-1] = static_cast<uint32_t>(bytes);
        }

        // Returns number of chars in the BSTR.
        size_t Length() const
        {
            return ::SysStringLen(bstr_);
        }

        // Returns the number of bytes allocated for the BSTR.
        size_t ByteLength() const
        {
            return ::SysStringByteLen(bstr_);
        }

        // Forbid comparison of ScopedBstr types.  You should never have the same
        // BSTR owned by two different scoped_ptrs.
        bool operator==(const ScopedBstr& bstr2) const = delete;
        bool operator!=(const ScopedBstr& bstr2) const = delete;

    protected:
        BSTR bstr_ = nullptr;
    };

    // Instantiates `wmi_services` with a connection to `server_name` in WMI. Will
    // set a security blanket if `set_blanket` is true.
    WmiError CreateLocalWmiConnection(
        const std::wstring& server_name,
        bool set_blanket,
        ComPtr<IWbemServices>* wmi_services)
    {
        ComPtr<IWbemLocator> wmi_locator;
        HRESULT hr =
            ::CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
                IID_PPV_ARGS(&wmi_locator));
        if (FAILED(hr))
            return WmiError::kFailedToCreateInstance;

        ComPtr<IWbemServices> wmi_services_r;
        hr = wmi_locator->ConnectServer(ScopedBstr(server_name).Get(),
            nullptr, nullptr, nullptr, 0, nullptr,
            nullptr, &wmi_services_r);
        if (FAILED(hr))
            return WmiError::kFailedToConnectToWMI;

        if (set_blanket)
        {
            hr = ::CoSetProxyBlanket(wmi_services_r.Get(), RPC_C_AUTHN_WINNT,
                RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
                RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
            if (FAILED(hr))
                return WmiError::kFailedToSetSecurityBlanket;
        }

        *wmi_services = std::move(wmi_services_r);
        return WmiError::kNoError;
    }

    // Runs `query` through `wmi_services` and sets the results' `enumerator`.
    bool TryRunQuery(const std::wstring& query,
        const ComPtr<IWbemServices>& wmi_services,
        ComPtr<IEnumWbemClassObject>* enumerator)
    {
        ScopedBstr query_language(L"WQL");
        ScopedBstr query_bstr(query);

        ComPtr<IEnumWbemClassObject> enumerator_r;
        HRESULT hr = wmi_services->ExecQuery(
            query_language.Get(), query_bstr.Get(),
            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
            &enumerator_r);

        if (FAILED(hr))
            return false;

        *enumerator = std::move(enumerator_r);
        return true;
    }

    class ScopedVariant
    {
    public:
        // Default constructor.
        ScopedVariant()
        {
            // This is equivalent to what VariantInit does, but less code.
            var_.vt = VT_EMPTY;
        }

        // Constructor to create a new VT_BSTR VARIANT.
        // NOTE: Do not pass a BSTR to this constructor expecting ownership to
        // be transferred
        ScopedVariant(const wchar_t* str)
        {
            var_.vt = VT_EMPTY;
            Set(str);
        }

        void Set(const wchar_t* str)
        {
            var_.vt = VT_BSTR;
            var_.bstrVal = ::SysAllocString(str);
        }

        inline VARTYPE type() const { return var_.vt; }

        // A hack to pass a pointer to the variant where the accepting
         // function treats the variant as an input-only, read-only value
         // but the function prototype requires a non const variant pointer.
         // There's no DCHECK or anything here.  Callers must know what they're doing.
        VARIANT* AsInput() const
        {
            // The nature of this function is const, so we declare
            // it as such and cast away the constness here.
            return const_cast<VARIANT*>(&var_);
        }

        // Allows const access to the contained variant without DCHECKs etc.
        // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to
        // work properly but still doesn't allow modifications since we want control
        // over that.
        const VARIANT* ptr() const { return &var_; }

        // Retrieves the pointer address.
          // Used to receive a VARIANT as an out argument (and take ownership).
          // The function DCHECKs on the current value being empty/null.
          // Usage: GetVariant(var.receive());
        VARIANT* Receive()
        {
            return &var_;
        }

    protected:
        VARIANT var_;
    };

}  // namespace

WmiError RunWmiQuery(const std::wstring& server_name,
    const std::wstring& query,
    ComPtr<IEnumWbemClassObject>* enumerator)
{
    ComPtr<IWbemServices> wmi_services;
    WmiError error = CreateLocalWmiConnection(server_name, /*set_blanket=*/true,
        &wmi_services);

    if (error != WmiError::kNoError)
        return error;

    if (!TryRunQuery(query, wmi_services, enumerator))
        return WmiError::kFailedToExecWMIQuery;

    return WmiError::kNoError;
}

bool CreateLocalWmiConnection(bool set_blanket,
    ComPtr<IWbemServices>* wmi_services)
{
    WmiError error =
        CreateLocalWmiConnection(kCimV2ServerName, set_blanket, wmi_services);
    return error != WmiError::kNoError;
}

bool CreateWmiClassMethodObject(IWbemServices* wmi_services,
    std::wstring class_name,
    std::wstring method_name,
    ComPtr<IWbemClassObject>* class_instance)
{
    // We attempt to instantiate a COM object that represents a WMI object plus
    // a method rolled into one entity.
    ScopedBstr b_class_name(class_name);
    ScopedBstr b_method_name(method_name);
    ComPtr<IWbemClassObject> class_object;
    HRESULT hr;
    hr = wmi_services->GetObject(b_class_name.Get(), 0, nullptr, &class_object,
        nullptr);
    if (FAILED(hr))
        return false;

    ComPtr<IWbemClassObject> params_def;
    hr = class_object->GetMethod(b_method_name.Get(), 0, &params_def, nullptr);
    if (FAILED(hr))
        return false;

    if (!params_def.Get())
    {
        // You hit this special case if the WMI class is not a CIM class. MSDN
        // sometimes tells you this. Welcome to WMI hell.
        return false;
    }

    hr = params_def->SpawnInstance(0, &(*class_instance));
    return SUCCEEDED(hr);
}

// The code in Launch() basically calls the Create Method of the Win32_Process
// CIM class is documented here:
// http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx
// NOTE: The documentation for the Create method suggests that the ProcessId
// parameter and return value are of type uint32_t, but when we call the method
// the values in the returned out_params, are VT_I4, which is int32_t.
bool WmiLaunchProcess(const std::wstring& command_line, int* process_id)
{
    ComPtr<IWbemServices> wmi_local;
    if (!CreateLocalWmiConnection(true, &wmi_local))
        return false;

    static constexpr wchar_t class_name[] = L"Win32_Process";
    static constexpr wchar_t method_name[] = L"Create";
    ComPtr<IWbemClassObject> process_create;
    if (!CreateWmiClassMethodObject(wmi_local.Get(), class_name, method_name,
        &process_create))
    {
        return false;
    }

    ScopedVariant b_command_line(command_line.c_str());

    if (FAILED(process_create->Put(L"CommandLine", 0, b_command_line.AsInput(),
        0)))
    {
        return false;
    }

    ComPtr<IWbemClassObject> out_params;
    HRESULT hr = wmi_local->ExecMethod(
        ScopedBstr(class_name).Get(), ScopedBstr(method_name).Get(), 0, nullptr,
        process_create.Get(), &out_params, nullptr);
    if (FAILED(hr))
        return false;

    // We're only expecting int32_t or uint32_t values, so no need for
    // ScopedVariant.
    VARIANT ret_value = { {{VT_EMPTY}} };
    hr = out_params->Get(L"ReturnValue", 0, &ret_value, nullptr, nullptr);
    if (FAILED(hr) || V_I4(&ret_value) != 0)
        return false;

    VARIANT pid = { {{VT_EMPTY}} };
    hr = out_params->Get(L"ProcessId", 0, &pid, nullptr, nullptr);
    if (FAILED(hr) || V_I4(&pid) == 0)
        return false;

    if (process_id)
        *process_id = V_I4(&pid);

    return true;
}

std::wstring WmiComputerSerialNumber::Bios()
{
    return Get(L"bios");
}

std::wstring WmiComputerSerialNumber::DiskDrive()
{
    return Get(L"hd");
}

std::wstring WmiComputerSerialNumber::Get(const std::wstring& id)
{
    std::wstring sql, key;
    for (const auto& iter : query_arr)
    {
        if (iter.id == id)
        {
            sql = iter.sql;
            key = iter.key;
        }
    }

    ComPtr<IEnumWbemClassObject> enumerator_bios;
    WmiError error =
        RunWmiQuery(kCimV2ServerName, sql.c_str(), &enumerator_bios);
    if (error != WmiError::kNoError)
        return std::wstring();

    std::wstring value;
    PopulateValue(enumerator_bios, key.c_str(), &value);
    return value;
}

void WmiComputerSerialNumber::PopulateValue(
    const ComPtr<IEnumWbemClassObject>& enumerator_bios,
    const std::wstring& key,
    std::wstring* output)
{
    ComPtr<IWbemClassObject> class_obj;
    ULONG items_returned = 0;
    HRESULT hr =
        enumerator_bios->Next(WBEM_INFINITE, 1, &class_obj, &items_returned);
    if (FAILED(hr) || !items_returned)
        return;

    ScopedVariant serial_number;
    hr = class_obj->Get(key.c_str(), 0, serial_number.Receive(), nullptr,
        nullptr);
    if (SUCCEEDED(hr) && serial_number.type() == VT_BSTR)
    {
        output->assign(V_BSTR(serial_number.ptr()),
            ::SysStringLen(V_BSTR(serial_number.ptr())));
    }
}

demo.cpp

#include <iostream>
#include "wmi_api.h"

int main()
{
    HRESULT hres;
    //初始化COM环境
    hres = ::CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres)) return 0;//初始化COM环境失败
    //设置COM安全等级
    hres = ::CoInitializeSecurity(
        NULL,
        -1,                          // COM 认证
        NULL,                        // 认证服务
        NULL,                        // 保留
        RPC_C_AUTHN_LEVEL_DEFAULT,   // 默认认证
        RPC_C_IMP_LEVEL_IMPERSONATE, // 默认模拟  
        NULL,                        // 认证信息
        EOAC_NONE,                   // 附加能力标志 
        NULL                         // 保留
    );

    WmiComputerSerialNumber wcsn;
    std::wcout << wcsn.Bios().c_str() << std::endl;
    std::wcout << wcsn.DiskDrive().c_str() << std::endl;

    ::CoUninitialize();

    system("pause");
}


    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/3008

    分享给朋友:

    “使用wmi获取电脑信息(bios序列号、磁盘序列号、cpu序列号、主板序列号、网卡序列号等)” 的相关文章

    Visual Studio编译7z源代码

    Visual Studio编译7z源代码

    源代码下载打开地址https://www.7-zip.org/download.html,选择源码下载,可以选择自己需要的版本下载7z.dll编译1:解压源代码包,打开vs解决方案,CPP7zipBundlesFormat7zFFormat7z.dsw,vs会提示升级,不用管,选择升级。2:修改7z...

    7z的简介和使用

    7z的简介和使用

    7z是一个支持多种压缩格式的开源项目,由Igor Pavlov开发,源码下载位置:https://www.7-zip.org/download.html源码结构项目源码目录结构是如下图:Asm包含主要算法实现的汇编代码,直接使用汇编的好处是可以提高运行效率,当然这对跨平台的支持不是很好。C主要是算法...

    使用GDI、MFC_GDI、GDI+绘制数组RGBA序列

    使用GDI、MFC_GDI、GDI+绘制数组RGBA序列

    学习ffmpeg时遇到一个问题,ffmpeg解码出RGB颜色后怎么绘制到屏幕上,于是将GDI、MFC_GDI、GDI+等方式都记录一下 1:注意按windows的要求,R、G、B、A顺序要调整为B、G、R、A 。 2:GDI不支持透明通道A,透明通道A的值读进去以后没有作用。想要支持透...

    ATL实现windows右键菜单扩展(ContextMenu)

    ATL实现windows右键菜单扩展(ContextMenu)

    右键菜单,即用户右击shell对象时弹出的上下文菜单(context menu)。本文记录了如何创建右键菜单的基本过程,跟着步骤一步一步来,即可创建出一个右键菜单工程。第一步,新建一个ATL工程Visual Studio—>新建项目—>ATL—>使用默认配置(一直按下一步即可)。注...

    uafxcwd.lib(afxmem.obj) : error LNK2005:

    uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)"解决办法

    如果在编译MFC程序的时候出现下列及类似的错误: 1˃uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) 已经在 LIBCMTD.lib(new...

    c++函数模板参数类型限定

    c++函数模板参数类型限定

    函数模板函数模板可以实现对不同数据类型做统一操作,比如比较两个数据的大小:template<typename T> bool compare(T& a,T& b) {   return a...