繁体   English   中英

通过C ++检查以太网上的Windows计算机

[英]Check if Windows Computer on Ethernet Via C++

所以我试着为此寻找几个不同的答案。 我认为可能有希望的是这一个:

如何在Windows上使用Qt检查网络接口类型是以太网还是无线?

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

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

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

但是,问题是我不知道如何检查设备是否已连接以太网。 有没有办法做到这一点? 我没有使用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;
}

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

我已经通过GetIfTableGetIfTable2获得了唯一有点可靠的方法,前者返回了一些肤浅的adpater信息 ,后者提供了很好的细节 下面是一个示例实现,因为它使用详细功能,您还可以查询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作为参数的上述功能基本相同...

首先,非常感谢用户@ Nighthawk441指出我正确的方向。 没有这个用户,我肯定没有提出解决方案。

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

简而言之,我所做的就是通过GetAdaptersInfo所有Adapters循环。 为了查看适配器是否已连接,我将适配器的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向我提供这些信息。 希望这会帮助别人! 如果有人有任何意见或任何其他答案,请随时发布! 谢谢!

基于@ 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM