【问题标题】:Check if Windows Computer on Ethernet Via C++检查以太网上的 Windows 计算机是否通过 C++
【发布时间】:2015-08-14 18:03:32
【问题描述】:

因此,我尝试查看几个不同的答案。我认为可能有希望的是这个:

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

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

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

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

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


编辑:我还应该包括到目前为止我已经尝试过的内容。

我尝试使用GetAdaptersInfo 并从PIP_ADAPTER_INFO 变量类型中获取Type 特征,但无论我是否在以太网上,这总是给我Unknown type 71

GetAdaptersInfo 的文档在这里: 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;
}

【问题讨论】:

  • 您有尝试使用 GetAdaptersInfo 的示例代码吗?
  • 我愿意;我现在将其添加为编辑。很抱歉没有包括在内!
  • @Nighthawk441 好的——我已将代码作为编辑包含在内。再次,抱歉之前缺少代码!谢谢你的评论:)
  • 我没有足够的信息来保证答案。但据我所知,GetAdaptersInfo 将返回所有已安装适配器的链接列表。您拥有的代码看起来像在 msdn 上找到的示例代码,它只检查第一个适配器。因此,您需要使用 IP_ADAPTER_INFO 中的 Next 指针遍历每个适配器。您可以获取每种适配器类型,但它不会说明它是否已连接。
  • @Nighthawk441 好吧,我没有意识到代码只检查了第一个适配器。我将循环遍历它们,然后尝试确定每个是否已连接。谢谢!

标签: c++ windows wireless ethernet


【解决方案1】:

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

我的经验是,唯一可靠的方法是通过GetIfTableGetIfTable2,前者返回一些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 (因为它是一个扩展) - 所以你需要一些 if/else 逻辑来将 WLAN 与非 WLAN 适配器分开。

您也可以使用WlanEnumInterfaces 来获取所有的WLAN 适配器,但这与以NdisPhysicalMediumNative802_11 作为参数使用上述函数基本相同...

【讨论】:

  • 这似乎是一个很好的答案,但不幸的是我有点困惑。一旦我像在第二个代码块中那样遍历向量,行的许多属性都是相同的。如何区分无线和有线?我如何知道用户是否连接到以太网?我尝试使用物理地址属性,但这些属性似乎没有给我 MAC 地址,所以我不确定要比较什么。对困惑感到抱歉。谢谢!
  • 好的,经过一些试验,我得到了这个答案。我将 if 语句更改为 if(row.Type == IF_TYPE_ETHERNET_CSMACD &amp;&amp; row.MediaConnectState == MdiaConnectStateConnected),然后在该 if 语句中返回 true。非常感谢您的时间和帮助。我现在会接受这个答案。
  • ^addendum:我还将发送给getDevices函数的参数更改为NdisPhysicalMedium802_3
【解决方案2】:

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

话虽如此,我现在的解决方案充其量只是一个 hack。它似乎有效,但我认为它甚至不接近最佳选择。因此,我将把它作为一个答案,但如果找到更好的答案,我暂时不会接受它。我也对任何人可能拥有的与此答案有关的任何 cmet 持开放态度。

简而言之,我所做的就是遍历来自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

非常感谢 Nighthawk 向我提供这些信息。希望这对其他人有帮助!如果有人有任何 cmets 或任何其他答案,请随时发布!谢谢!

【讨论】:

  • 我以为这应该是 C++?这段代码充满了令人作呕的手动内存管理。
  • 这是一个初学者的尝试......不要评判他 - 而是详细指出缺陷并提供如何完成的示例。
  • @Puppy 此代码表面上是直接从我在回答中提到的 MSDN 参考中复制的。我总共添加了一个 [1] 更多 free(...) 声明。如果内存管理有问题,那我就不得不转而说这是 MSDN 文档的问题。
  • ^当我说答案时,我当然是指我的问题。文档是here
  • MSDN 以拥有可怕的示例而闻名……很可能,没有经验的 Web 开发人员一直在编写它们。最好不要复制/粘贴它们,而是查看 CORE 功能并使用它 - 不仅许多示例充满错误,而且有时还存在巨大的安全风险
【解决方案3】:

根据@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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多