代码之家  ›  专栏  ›  技术社区  ›  shovel_coder

检查Windows计算机是否通过C以太网++

  •  3
  • shovel_coder  · 技术社区  · 9 年前

    因此,我尝试了寻找一些不同的答案。我认为可能会有这样一个承诺:

    How to check network interface type is Ethernet or Wireless on Windows using Qt?

    然而,我对网络甚至Windows都不太了解。就我个人而言,我无法理解他们网站上的大多数Microsoft文档。我尝试过 INetworkConnection , NativeWiFi 等等。但要么他们没有做我想做的事,要么我就是无法从可用的文档中找出如何做。

    话虽如此,我想用C++检查运行该程序的设备是否通过以太网电缆连接到互联网。基本上,我想做以下工作:

    • 如果计算机仅连接到无线,请运行程序
    • 如果计算机仅连接到Wired,则不要运行该程序
    • 如果计算机同时连接到有线和无线,则不要运行该程序

    然而,问题是我不知道如何检查设备是否连接了以太网。有办法做到这一点吗?我没有使用QT。非常感谢。


    编辑:我还应该包括我迄今为止所做的努力。

    我试过使用 GetAdaptersInfo 并获得 Type 来自 PIP_ADAPTER_INFO 变量类型,但这总是给我 Unknown type 71 无论我是否在以太网上。

    相关文件 获取适配器信息 在这里: https://msdn.microsoft.com/en-us/library/aa365917%28VS.85%29.aspx

    谢谢


    编辑2:这是我用于GetAdaptersInfo的代码

    bool is_on_ethernet{
        PIP_ADAPTER_INFO pAdapterInfo;
        PIP_ADAPTER_INFO pAdapter = NULL;
        DWORD dwRetVal = 0;
        UINT i;
    
        struct tm newtime;
        char buffer[32];
        errno_t error;
    
        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
        pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    
        if(pAdapterInfo == NULL)
            printf("Error allocating memory need to call GetAdaptersInfo");
    
        if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
            free(pAdapterInfo);
            pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
        }
    
        if((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
            pAdapter = pAdapterInfo;
    
            switch(pAdapter->Type){
                case MIB_IF_TYPE_OTHER:
                    printf("Other\n");
                    return false;
                    break;
                case MIB_IF_TYPE_ETHERNET:
                    printf("Ethernet\h");
                    return true;
                    break;
                case MIB_IF_TYPE_TOKENRING:
                    printf("Token Ring\n");
                    return false;
                    break;
                case MIB_IF_TYPE_FDDI
                    printf("FDDI\n");
                    return false;
                    break;
                case MIB_IF_TYPE_PPP
                    printf("PPP\n");
                    return false;
                    break;
                case MIB_IF_TYPE_LOOPBACK
                    printf("Lookback\n");
                    return false;
                    break;
                case MIB_IF_TYPE_SLIP
                    printf("Slip\n");
                    return false;
                    break;
                default
                    printf("Unknown type %ld\n\n", pAdapter->Type);
                    return false;
                    break;
            }
        }
    
        if(pAdapterInfo)
            free(pAdapterInfo);
    
        return false;
    }
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   specializt    9 年前

    您的问题有些困难,因为获取“当前”网络适配器可能非常复杂——windows根据网络适配器配置和目标可达性来路由数据包,因此您的“当前”适配器可能随时更改……但由于您已经知道如何检索可用适配器的IP和MAC(“硬件地址”),因此您可以简单地使用黑客来检索MAC用于您当前的IP,并在我的第二个功能中进行过滤/搜索!字段“PhysicalAddress”是您要查找的地址,即MAC地址

    我有过这样的经历:唯一的、有点可靠的方法是通过 GetIfTable GetIfTable2 ,前者有所回归 superficial adpater info 后者提供了 detail . 这是一个示例实现,因为它使用了详细的功能,您还可以查询WLAN适配器:

    vector<MIB_IF_ROW2>* getDevices(NDIS_PHYSICAL_MEDIUM type)
        {       
            vector<MIB_IF_ROW2> *v = new vector<MIB_IF_ROW2>();
            PMIB_IF_TABLE2 table = NULL;
            if(GetIfTable2Ex(MibIfTableRaw, &table) == NOERROR && table)
            {
                UINT32 i = 0;
                for(; i < table->NumEntries; i++)
                {
                    MIB_IF_ROW2 row;
    
                    ZeroMemory(&row, sizeof(MIB_IF_ROW2));
                    row.InterfaceIndex = i;
                    if(GetIfEntry2(&row) == NOERROR)
                    {                   
                        if(row.PhysicalMediumType == type)
                        {
                            v->push_back(row);
                        }                   
                    }           
                }
                FreeMibTable(table);
            }
            return v;
        }
    

    现在,您需要做的就是遍历列表并过滤掉禁用的适配器等:

    vector<MIB_IF_ROW2>* wlan = getDevices(NdisPhysicalMediumNative802_11); //WLAN adapters
    //see https://msdn.microsoft.com/en-us/library/windows/desktop/aa814491(v=vs.85).aspx, "PhysicalMediumType" for a full list
    for(auto &row : *v)
        {
            //do some additional filtering, this needs to be changed for non-WLAN           
            if( row.TunnelType == TUNNEL_TYPE_NONE &&
                row.AccessType != NET_IF_ACCESS_LOOPBACK &&         
                row.Type == IF_TYPE_IEEE80211 &&
                row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE)              
                {
                    //HERE BE DRAGONS!                    
                }
        }
    

    现在很容易生成WLAN适配器和非WLAN适配器的列表 (参见第二个函数中的注释) ,搜索您当前的MAC并得出结论:它是有线或无线的,但请注意这些列表 也许 重叠,因为 802.11 基本上是的扩展版本 802.3 但是 802.3有 包括802.11 (因为它是一个扩展) -因此,为了将WLAN与非WLAN适配器区分开来,您需要一点if/else逻辑。

    您也可以使用 WlanEnumInterfaces 获取所有WLAN适配器,但基本上与使用上面的功能相同 NdisPhysicalMediumNative802_11 作为参数。。。

        2
  •  0
  •   shovel_coder    9 年前

    首先,非常感谢用户@Nighthawk441为我指明了正确的方向。如果没有这个用户,我肯定不会想出解决方案。

    话虽如此,我现在的解决方案充其量就是破解。这似乎是可行的,但我认为这甚至不是最佳选择。因此,我将把这作为一个答案,但如果找到更好的答案,我暂时不会接受它。我也非常乐意接受任何人对这个答案的评论。

    简而言之,我所做的是从 GetAdaptersInfo 。为了查看适配器是否已连接,我将适配器的IP地址与字符串进行了比较 "0.0.0.0" ,就好像是其他东西一样,我觉得可以安全地说适配器已连接。所以,不用多说,这里是我实现的代码。

    bool is_on_ethernet(){
        PIP_ADAPTER_INFO pAdapterInfo;
        PIP_ADAPTER_INFO pAdapter = NULL;
        DWORD dwRetVal = 0;
        UINT i;
    
        struct tm newtime;
        char buffer[32];
        errno_t error;
    
        ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
        pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
    
        if(pAdapterInfo == NULL)
            printf("Error allocating memory needed to call GetAdaptersInfo");
    
        if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW){
            free(pAdapterInfo);
            pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
        }
    
        if((dwRetValue = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR){
            do{
                pAdapter = pAdapterInfo;
    
                string ip_string = pAdapter->IpAddressList.IpAddress.String;
    
                switch(pAdapter->Type){
                    case MIB_IF_TYPE_OTHER:
                        printf("Other\n");
                        break;
                    ...
                    case MIB_IF_TYPE_ETHERNET:
                        printf("Ethernet\n");
    
                        //new code
                        if(ip_string.compare("0.0.0.0") != 0){
                            free(pAdapterInfo);
                            return true;
                        }
    
                        break;
                    default:
                        printf("Unknown type %ld\n", pAdapter->Type);
                        break;
                }
            }while(pAdapterInfo = pAdapterInfo->Next);
        }
    
        if(pAdapterInfo)
            free(pAdapterInfo);
    
        return false;
    }
    

    看看这个参考资料真的帮了我:

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa365819%28v=vs.85%29.aspx

    因此,感谢夜鹰向我提供了这些信息。希望这对其他人有所帮助!如果有人有任何意见或任何其他答案,请随时发布!谢谢

        3
  •  0
  •   yuanen cao    5 年前

    根据@specializt的回答,经过一些小的修改,我的工作如下:

    BOOL getDevices(NDIS_PHYSICAL_MEDIUM type, vector<MIB_IF_ROW2>& vetIFRow)
    {
        PMIB_IF_TABLE2 table = NULL;
        if (GetIfTable2Ex(MibIfTableRaw, &table) != NOERROR || !table)
        {
            return FALSE;
        }
    
        for (ULONG i = 0; i < table->NumEntries; i++)
        {
            MIB_IF_ROW2 row;
            ZeroMemory(&row, sizeof(MIB_IF_ROW2));
            row.InterfaceIndex = i;
            if (GetIfEntry2(&row) == NOERROR && row.PhysicalMediumType == type)
            {
                vetIFRow.push_back(row);
            }
        }
    
        FreeMibTable(table);
        return TRUE;
    }
    
    BOOL isNetIFConnected(const MIB_IF_ROW2& row, IFTYPE Type)
    {
        return (row.TunnelType == TUNNEL_TYPE_NONE &&
            row.AccessType != NET_IF_ACCESS_LOOPBACK &&
            row.Type == Type &&
            row.InterfaceAndOperStatusFlags.HardwareInterface == TRUE &&
            row.MediaConnectState == MediaConnectStateConnected);
    }
    
    tstring getNetWorkType()
    {
        vector<MIB_IF_ROW2> vectRow;
        BOOL bRet = getDevices(NdisPhysicalMedium802_3, vectRow); // ETHERNET adapters
        if (bRet)
        {
            for (auto it = vectRow.begin(); it != vectRow.end(); it++)
            {
                if (isNetIFConnected(*it, IF_TYPE_ETHERNET_CSMACD))
                {
                    return L"ETHERNET";
                }
            }
        }
    
        vectRow.clear();
        bRet = getDevices(NdisPhysicalMediumNative802_11, vectRow); //WLAN adapters
        if (bRet)
        {
            for (auto it = vectRow.begin(); it != vectRow.end(); it++)
            {
                if (isNetIFConnected(*it, IF_TYPE_IEEE80211))
                {
                    return L"WIFI";
                }
            }
        }
    
        return L"Unknown";
    }
    

    感谢@specializt