문제

우리는 현재 사용 중입니다 netbios 방법, XP에서는 괜찮습니다. Vista의 예비 테스트에 따르면 그것이 효과가 있지만 경고가 있음을 보여줍니다. 예를 들어 Netbios가 존재해야하며, 내가 읽은 내용에서 어댑터의 순서가 변경되어야합니다. 우리의 대체 방법 - snmpextensionquery - 비스타 아래에서 깨진 것 같습니다.

문제는 : Vista 기계에서 로컬 MAC 주소 목록을 얻는 신뢰할 수있는 방법을 알고 있습니까? XP와의 거꾸로 호환성은 플러스입니다 (나는 추악한 #ifdef 's보다 하나의 단일 방법을 가질 것입니다). 감사!

도움이 되었습니까?

해결책

당신은 그것을 사용할 수 있습니까? wmiservice? 그래도 비스타 전 시절에 기계의 MAC 주소를 얻는 데 사용했습니다.

다른 팁

컴퓨터의 모든 MAC 주소 목록을 제공합니다. 모든 버전의 Windows에서도 작동합니다.

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 ()는 공식적인 방법이며 모든 어댑터를 연결 해제 한 어댑터조차 열거합니다.
예를 들어이 게시물을 참조하십시오 코드 구루

#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";
}

XP와 Vista에서 WMI를 사용할 수 있으며 온라인으로 여러 가지 예가 있습니다. 예 :WMI (Windows Management Instrumentation)를 사용하여 Mac 주소를 얻습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top