ج++:الحصول على عنوان MAC لمحولات الشبكة على نظام التشغيل Vista؟

StackOverflow https://stackoverflow.com/questions/221894

  •  03-07-2019
  •  | 
  •  

سؤال

نحن نستخدم حاليا طريقة نت بيوس, ، ويعمل بشكل جيد تحت XP.تظهر الاختبارات الأولية في نظام التشغيل Vista أنه يعمل أيضًا، ولكن هناك تحذيرات - يجب أن يكون NetBIOS موجودًا، على سبيل المثال، ومن ما كنت أقرأه، لا بد أن يتغير ترتيب المحولات.طريقتنا البديلة - مع SNMPExtensionQuery - يبدو أن تكون مكسورة تحت ويندوز فيستا.

السؤال هو:هل تعرف طريقة موثوقة للحصول على قائمة بعناوين MAC المحلية على جهاز يعمل بنظام Vista؟يعد التوافق مع الإصدارات السابقة مع XP ميزة إضافية (أفضل أن يكون لدي طريقة واحدة بدلاً من الكثير من الطرق #ifdef القبيحة).شكرًا!

هل كانت مفيدة؟

المحلول

ويمكن استخدام WMIService ؟ اعتدت عليه للحصول على ماك-عنوان الجهاز في أيام ما قبل فيستا بالرغم من ذلك.

نصائح أخرى

وهذا سوف أعطيك قائمة من كافة عناوين MAC على الكمبيوتر الخاص بك. وسوف يعمل مع جميع إصدارات ويندوز وكذلك:

void getdMacAddresses(std::vector<std::string> &vMacAddresses;)
{
    vMacAddresses.clear();
    IP_ADAPTER_INFO AdapterInfo[32];       // Allocate information for up to 32 NICs
    DWORD dwBufLen = sizeof(AdapterInfo);  // Save memory size of buffer
    DWORD dwStatus = GetAdaptersInfo(      // Call GetAdapterInfo
    AdapterInfo,                 // [out] buffer to receive data
    &dwBufLen);                  // [in] size of receive data buffer

    //No network card? Other error?
    if(dwStatus != ERROR_SUCCESS)
        return;

    PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
    char szBuffer[512];
    while(pAdapterInfo)
    {
        if(pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)
        {
            sprintf_s(szBuffer, sizeof(szBuffer), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x"
                , pAdapterInfo->Address[0]
                , pAdapterInfo->Address[1]
                , pAdapterInfo->Address[2]
                , pAdapterInfo->Address[3]
                , pAdapterInfo->Address[4]
                , pAdapterInfo->Address[5]
                );
            vMacAddresses.push_back(szBuffer);
        }
        pAdapterInfo = pAdapterInfo->Next;

    }
}

وقديم السؤال، أجاب بالفعل، ولكن هذا هو رمز أكثر أمانا - في حالة WMI لا يمكن تهيئة تماما

لتحصل على الوصول إلى المعلومات حول النظام الخاص بك، وهنا هي فئة الحد الأدنى الذي يحاول البقاء آمنة:

ملحوظة: يتم ترك ToString، convertToUtf8 وconvertFromUtf8 باعتبارها ممارسة للقارئ. :)

ملحوظة: لقد أظهرت فقط <م> آمنة التهيئة والمسيل للدموع لأسفل من نظام WMI، وأساسيات الحصول على القيم من WMI، والحصول على عناوين MAC (السؤال في OP) .

وهذا <م> جاء من قانون العمل، ولكن تم تعديله لأنني لصقها هنا. لذلك فمن الممكن أشياء أخرى حصلت استبعد أن استحق المدرجة. عفوا.

class WmiAccessor
{
public:
    WmiAccessor()
        : _pWbemLocator(NULL)
        , _pWbemServices(NULL)
        , _com_initialized(false)
        , _com_need_uninitialize(false)
        , _svc_initialized(false)
        , _loc_initialized(false)
        , _all_initialized(false)
        , _errors("")
        , m_mutex()
    {
        HRESULT hr;
        hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        switch (hr)
        {
        case S_OK:
            // The COM library was initialized successfully on this thread.
            _com_initialized = true;
            _com_need_uninitialize = true;
            break;
        case S_FALSE:
            // The COM library is already initialized on this thread.
            _com_initialized = true;
            _com_need_uninitialize = true;
            break;
        case RPC_E_CHANGED_MODE:
            // A previous call to CoInitializeEx specified the concurrency model
            // for this thread as multithread apartment (MTA).
            //  This could also indicate that a change from neutral-threaded apartment to
            //  single-threaded apartment has occurred.
            _com_initialized = true;
            _com_need_uninitialize = false;
            break;
        default:
            _com_initialized = false;
            _com_need_uninitialize = false;
            _errors += "Failed to initialize COM.\r\n";
            return;
        }

        hr = ::CoInitializeSecurity(NULL, -1, NULL, NULL,
            0 /*RPC_C_AUTHN_LEVEL_DEFAULT*/,
            3 /*RPC_C_IMP_LEVEL_IMPERSONATE*/,
            NULL, EOAC_NONE, NULL);
        // RPC_E_TOO_LATE == Security must be initialized before!
        // It cannot be changed once initialized. I don't care!
        if (FAILED(hr) && (hr != RPC_E_TOO_LATE))
        {
            _errors += "Failed to initialize COM Security.\r\n";
            if (_com_need_uninitialize)
            {
                ::CoUninitialize();
                _com_need_uninitialize = false;
            }
            return;
        }

        hr = _pWbemLocator.CoCreateInstance(CLSID_WbemLocator);
        if (FAILED(hr) || (_pWbemLocator == nullptr))
        {
            _errors += "Failed to initialize WBEM Locator.\r\n";
            return;
        }
        _loc_initialized = true;

        hr = _pWbemLocator->ConnectServer(
            CComBSTR(L"root\\cimv2"), NULL, NULL, 0, NULL, 0, NULL, &_pWbemServices);
        if (FAILED(hr) || (_pWbemServices == nullptr))
        {
            _errors += "Failed to connect WBEM Locator.\r\n";
            _pWbemLocator.Release();
            _loc_initialized = false;
            return;
        }
        else
        {
            _svc_initialized = true;

            // Set security Levels on the proxy
            hr = CoSetProxyBlanket(_pWbemServices,
                RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
                RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
                NULL,                        // Server principal name
                RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
                RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
                NULL,                        // client identity
                EOAC_NONE                    // proxy capabilities
            );
            if (FAILED(hr))
            {
                _errors += "Failed to set proxy blanket.\r\n";
                return;
            }
        }

        _all_initialized = true;
    }

    ~WmiAccessor()
    {
        std::unique_lock<std::mutex> slock(m_mutex);

        if (_svc_initialized)
        {
            if (_pWbemServices)
                _pWbemServices.Release();
            _svc_initialized = false;
        }
        if (_loc_initialized)
        {
            if (_pWbemLocator)
                _pWbemLocator.Release();
            _loc_initialized = false;
        }
        if (_com_initialized)
        {
            if (_com_need_uninitialize)
            {
                ::CoUninitialize();
            }
            _com_initialized = false;
            _com_need_uninitialize = false;
        }
        _all_initialized = false;
    }

    // public: must lock
    std::string get_and_clear_errors()
    {
        std::string result = "";
        std::unique_lock<std::mutex> slock(m_mutex);
        std::swap(result, _errors);
        return result;
    }

    // public: must lock
    std::string get_string(const std::string& name, const std::string& dflt /*= ""*/)
    {
        std::unique_lock<std::mutex> slock(m_mutex);
        return _all_initialized ? _string(name) : dflt;
    }

    // public: must lock
    uint32_t get_uint32(const std::string& name, uint32_t dflt /*= 0*/)
    {
        std::unique_lock<std::mutex> slock(m_mutex);
        return _all_initialized ? _uint32(name) : dflt;
    }


    // similarly for other public accessors of basic types.


private:
    CComPtr<IWbemLocator> _pWbemLocator;
    CComPtr<IWbemServices> _pWbemServices;
    volatile bool _com_initialized;
    volatile bool _com_need_uninitialize;
    volatile bool _svc_initialized;
    volatile bool _loc_initialized;
    volatile bool _all_initialized;
    std::string _errors;
    CComVariant _variant(const std::wstring& name);
    std::string _string(const std::string& name);
    uint32_t _uint32(const std::string& name);
    uint16_t _uint16(const std::string& name);
    uint8_t _uint8(const std::string& name);
    std::vector<std::string> _macAddresses(bool forceReCalculate = false);
    // to protect internal objects, public methods need to protect the internals.
    //
    mutable std::mutex m_mutex;
    std::vector<std::string> _macs; // unlikely to change, so save them once found.

    // internal: assumes inside a lock
    CComVariant _variant(const std::wstring& name)
    {
        if (!_all_initialized)
            return CComVariant();

        CComPtr<IEnumWbemClassObject> pEnum;
        CComBSTR cbsQuery = std::wstring(L"Select " + name + L" from Win32_OperatingSystem").c_str();
        HRESULT hr = _pWbemServices->ExecQuery(
            CComBSTR(L"WQL"), cbsQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
        CComVariant cvtValue;
        if (FAILED(hr) || !pEnum)
        {
            std::wstring wquery(cbsQuery, SysStringLen(cbsQuery));
            _errors += "Failed to exec WMI query: '" + convertToUtf8(wquery) + "'\r\n";
            return cvtValue;
        }
        ULONG uObjectCount = 0;
        CComPtr<IWbemClassObject> pWmiObject;
        hr = pEnum->Next(WBEM_INFINITE, 1, &pWmiObject, &uObjectCount);
        if (FAILED(hr) || !pWmiObject)
        {
            _errors
                += "Failed to get WMI Next result for: '" + convertToUtf8(name) + "'\r\n";
            return cvtValue;
        }
        hr = pWmiObject->Get(name.c_str(), 0, &cvtValue, 0, 0);
        if (FAILED(hr))
        {
            _errors
                += "Failed to get WMI result value for: '" + convertToUtf8(name) + "'\r\n";
        }
        return cvtValue;
    }

    // internal: assumes inside a lock
    std::string _string(const std::string& name)
    {
        if (!_all_initialized)
            return "";

        CComVariant cvtValue = _variant(convertFromUtf8(name).c_str());
        std::wstring wValue(cvtValue.bstrVal, SysStringLen(cvtValue.bstrVal));
        std::string sValue = convertToUtf8(wValue);
        return sValue;
    }

    // internal: assumes inside a lock
    uint32_t _uint32(const std::string& name)
    {
        if (!_all_initialized)
            return 0;

        CComVariant cvtValue = _variant(convertFromUtf8(name).c_str());
        uint32_t uValue = static_cast<uint32_t>(cvtValue.lVal);
        return uValue;
    }

    // similarly for other internal access of basic types.

    // internal: assumes inside a lock
    std::vector<std::string> _macAddresses(bool forceReCalculate /*= false*/)
    {
        if (!_all_initialized)
        {
            return _macs; // it will still be empty at this point.
        }
        if (forceReCalculate)
        {
            _macs.clear();
        }
        if (_macs.empty())
        {
            // hr == 0x80041010 == WBEM_E_INVALID_CLASS
            // hr == 0x80041017 == WBEM_E_INVALID_QUERY
            // hr == 0x80041018 == WBEM_E_INVALID_QUERY_TYPE
            CComBSTR cbsQuery = std::wstring(L"Select * from Win32_NetworkAdapter").c_str();
            CComPtr<IEnumWbemClassObject> pEnum;
            HRESULT hr = _pWbemServices->ExecQuery(
                CComBSTR(L"WQL"), cbsQuery, WBEM_RETURN_IMMEDIATELY, NULL, &pEnum);
            if (FAILED(hr))
            {
                _errors += "error: MacAddresses: ExecQuery('"
                           + convertToUtf8((LPWSTR)cbsQuery) + "') returned "
                           + ToString(hr) + "\r\n";
            }
            if (SUCCEEDED(hr))
            {
                ULONG fetched;
                VARIANT var;
                IWbemClassObject* pclsObj = NULL;
                while (pEnum)
                {
                    hr = pEnum->Next(WBEM_INFINITE, 1, &pclsObj, &fetched);
                    if (0 == fetched)
                        break;

                    std::string theMac = "";
                    VariantInit(&var);
                    hr = pclsObj->Get(L"MACAddress", 0, &var, 0, 0);
                    if (SUCCEEDED(hr))
                    {
                        switch (var.vt)
                        {
                            case VT_NULL: break;
                            case VT_BSTR:
                                theMac = (var.bstrVal == NULL)
                                       ? ""
                                       : convertToUtf8(var.bstrVal);
                                break;
                            case VT_LPSTR:
                                theMac = (var.bstrVal == NULL)
                                       ? ""
                                       : (const char*)var.bstrVal;
                                break;
                            case VT_LPWSTR:
                                theMac = (var.bstrVal == NULL)
                                       ? ""
                                       : convertToUtf8((LPWSTR)var.bstrVal);
                                break;
                            // _could_ be array of BSTR, LPSTR, LPWSTR; unlikely, but ....
                            case VT_ARRAY | VT_BSTR:
                            case VT_ARRAY | VT_LPSTR:
                            case VT_ARRAY | VT_LPWSTR:
                                _errors += "warning: MacAddresses: unexpected array of addresses";
                                _errors += "\r\n";

                                // yet another exercise for the reader :)
                                break;
                            default:
                                _errors += "error: MacAddresses: unexpected VARIANT.vt =  "
                                       + ToString(var.vt) + "\r\n";
                                break;
                        }
                        // local loopback has an empty address?
                        if (!theMac.empty())
                        {
                            _macs.push_back(theMac);
                        }
                    }
                    VariantClear(&var);
                    pclsObj->Release();
                }
            }
        }
        return _macs;
    }

...

}

GetAdaptersInfo() هي الطريقة الرسمية، فهي تقوم بتعداد جميع المحولات حتى تلك التي تم قطع اتصالها.
انظر هذا المنشور على سبيل المثال الكود com.codeguru

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdio.h>
#include <vector>
#include <Windows.h>
#include <Iphlpapi.h>
#include <Assert.h>
#include <string>
#pragma comment(lib, "iphlpapi.lib")


char* getdMacAddresses()
{

    IP_ADAPTER_INFO AdapterInfo[32];       // Allocate information for up to 32 NICs
    DWORD dwBufLen = sizeof(AdapterInfo);  // Save memory size of buffer
    DWORD dwStatus = GetAdaptersInfo(      // Call GetAdapterInfo
        AdapterInfo,                 // [out] buffer to receive data
        &dwBufLen);                  // [in] size of receive data buffer

    //Exit When Error 
    if (dwStatus != ERROR_SUCCESS)
        return "ERROR";

    PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
    char szBuffer[512];
    while (pAdapterInfo)
    {
        if (pAdapterInfo->Type == MIB_IF_TYPE_ETHERNET)
        {

            sprintf_s(szBuffer, sizeof(szBuffer), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x"
                , pAdapterInfo->Address[0]
                , pAdapterInfo->Address[1]
                , pAdapterInfo->Address[2]
                , pAdapterInfo->Address[3]
                , pAdapterInfo->Address[4]
                , pAdapterInfo->Address[5]
                );

            return szBuffer; 

        }


        pAdapterInfo = pAdapterInfo->Next;

    }

    return "ERROR";
}

ويمكنك استخدام WMI على حد سواء XP وفيستا، وهناك عدد من الأمثلة على الانترنت. منها مثلا: استخدام Windows Management Instrumentation (WMI) للحصول على MAC عنوان

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top