Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WinUI] Add workaround for Connectivity check on Win10 #19261

Merged
merged 13 commits into from
Jan 23, 2024
173 changes: 173 additions & 0 deletions src/Essentials/src/Connectivity/Connectivity.Native.uwp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Microsoft.Maui.Networking
{
#if WINDOWS
internal class ConnectivityNativeHelper
{
internal static string CNetworkListManagerCoClassGuid = "DCB00C01-570F-4A9B-8D69-199FDBA5723B";

internal enum NLM_ENUM_NETWORK : int
{
NLM_ENUM_NETWORK_CONNECTED = 0x01,
NLM_ENUM_NETWORK_DISCONNECTED = 0x02,
NLM_ENUM_NETWORK_ALL = 0x03
}

internal enum NLM_NETWORK_CATEGORY
{
NLM_NETWORK_CATEGORY_PUBLIC = 0x00,
NLM_NETWORK_CATEGORY_PRIVATE = 0x01,
NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED = 0x02
}

[Flags]
internal enum NLM_CONNECTIVITY
{
NLM_CONNECTIVITY_DISCONNECTED = 0,
NLM_CONNECTIVITY_IPV4_NOTRAFFIC = 0x1,
NLM_CONNECTIVITY_IPV6_NOTRAFFIC = 0x2,
NLM_CONNECTIVITY_IPV4_SUBNET = 0x10,
NLM_CONNECTIVITY_IPV4_LOCALNETWORK = 0x20,
NLM_CONNECTIVITY_IPV4_INTERNET = 0x40,
NLM_CONNECTIVITY_IPV6_SUBNET = 0x100,
NLM_CONNECTIVITY_IPV6_LOCALNETWORK = 0x200,
NLM_CONNECTIVITY_IPV6_INTERNET = 0x400
}

[ComImport]
[Guid("DCB00000-570F-4A9B-8D69-199FDBA5723B")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface INetworkListManager
{
IEnumNetworks GetNetworks(NLM_ENUM_NETWORK flags);

INetwork GetNetwork(Guid guid);

IEnumNetworkConnections GetNetworkConnections();

void GetNetworkConnection();

bool IsConnectedToInternet { get; }

bool IsConnected { get; }

void GetConnectivity();
}

[ComImport]
[Guid("DCB00003-570F-4A9B-8D69-199FDBA5723B")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IEnumNetworks : IEnumerable
{
}

[ComImport]
[Guid("DCB00006-570F-4A9B-8D69-199FDBA5723B")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IEnumNetworkConnections : IEnumerable<int>
{
}

[ComImport]
[Guid("DCB00002-570F-4A9B-8D69-199FDBA5723B")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface INetwork
{
/// <summary>
/// Get the name of the network.
/// </summary>
/// <returns>The network name.</returns>
string GetName();

/// <summary>
/// Rename this network. This change takes effect immediately.
/// </summary>
/// <param name="szNetworkNewName"></param>
void SetName(string szNetworkNewName);

/// <summary>
/// Get the network description.
/// </summary>
/// <returns>Network description.</returns>
string GetDescription();

/// <summary>
/// Set the network description. This change takes effect immediately.
/// </summary>
/// <param name="szDescription">The network description.</param>
/// /// <returns></returns>
void SetDescription(string szDescription);

/// <summary>
/// Get the network ID.
/// </summary>
/// <returns>The network Id.</returns>
Guid GetNetworkId();

/// <summary>
/// Returns the domain type of a network.
/// </summary>
/// <returns>Domain Type</returns>
Int32 GetDomainType();

/// <summary>
/// Returns an enumeration of all network connections for a network
/// </summary>
/// <returns>Network Enumeration</returns>
IEnumNetworkConnections GetNetworkConnections();

/// <summary>
/// Returns the local date and time when the network was created and connected.
/// </summary>
/// <param name="pdwLowDateTimeCreated"></param>
/// <param name="pdwHighDateTimeCreated"></param>
/// <param name="pdwLowDateTimeConnected"></param>
/// <param name="pdwHighDateTimeConnected"></param>
void GetTimeCreatedAndConnected(
out uint pdwLowDateTimeCreated,
out uint pdwHighDateTimeCreated,
out uint pdwLowDateTimeConnected,
out uint pdwHighDateTimeConnected);

/// <summary>
/// Specifies if the network has internet connectivity.
/// </summary>
/// <returns></returns>
bool IsConnectedToInternet();

/// <summary>
/// Specifies if the network has any network connectivity.
/// </summary>
/// <returns></returns>
bool IsConnected();

/// <summary>
/// Returns the connectivity state of the network.
/// </summary>
/// <returns></returns>
NLM_CONNECTIVITY GetConnectivity();

/// <summary>
/// Returns the category of a network.
/// </summary>
/// <returns></returns>
NLM_NETWORK_CATEGORY GetCategory();

void SetCategory(NLM_NETWORK_CATEGORY NewCategory);
}

internal static INetworkListManager GetNetworkListManager()
{
Type netProfMgrClass = Type.GetTypeFromCLSID(new Guid(CNetworkListManagerCoClassGuid));

#pragma warning disable IL2072
return (INetworkListManager)Activator.CreateInstance(netProfMgrClass);
#pragma warning restore
}
}
#endif
}
110 changes: 67 additions & 43 deletions src/Essentials/src/Connectivity/Connectivity.uwp.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using Windows.Networking.Connectivity;

namespace Microsoft.Maui.Networking
Expand All @@ -21,62 +20,87 @@ public NetworkAccess NetworkAccess
{
get
{
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile == null)
return NetworkAccess.Unknown;
if (OperatingSystem.IsWindowsVersionAtLeast(11))
{
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile == null)
return NetworkAccess.Unknown;

var level = profile.GetNetworkConnectivityLevel();
return level switch
var level = profile.GetNetworkConnectivityLevel();
return level switch
{
NetworkConnectivityLevel.LocalAccess => NetworkAccess.Local,
NetworkConnectivityLevel.InternetAccess => NetworkAccess.Internet,
NetworkConnectivityLevel.ConstrainedInternetAccess => NetworkAccess.ConstrainedInternet,
_ => NetworkAccess.None,
};
}
else
{
NetworkConnectivityLevel.LocalAccess => NetworkAccess.Local,
NetworkConnectivityLevel.InternetAccess => NetworkAccess.Internet,
NetworkConnectivityLevel.ConstrainedInternetAccess => NetworkAccess.ConstrainedInternet,
_ => NetworkAccess.None,
};
// Windows 10 workaround for https://github.com/microsoft/WindowsAppSDK/issues/2965
var networkList = ConnectivityNativeHelper.GetNetworkListManager();
var enumNetworks = networkList.GetNetworks(ConnectivityNativeHelper.NLM_ENUM_NETWORK.NLM_ENUM_NETWORK_CONNECTED);
var connectivity = ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_DISCONNECTED;

foreach (ConnectivityNativeHelper.INetwork networkInterface in enumNetworks)
{
if (networkInterface.IsConnected())
{
connectivity = networkInterface.GetConnectivity();
break;
}
}

if ((connectivity & (ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV4_INTERNET | ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV6_INTERNET)) != 0)
{
return NetworkAccess.Internet;
}
else if ((connectivity & (ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV4_LOCALNETWORK | ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV6_LOCALNETWORK)) != 0)
{
return NetworkAccess.Local;
}
else if ((connectivity & (ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV4_NOTRAFFIC | ConnectivityNativeHelper.NLM_CONNECTIVITY.NLM_CONNECTIVITY_IPV6_NOTRAFFIC)) != 0)
{
return NetworkAccess.Local;
}
else
{
return NetworkAccess.None;
}
}
}
}

public IEnumerable<ConnectionProfile> ConnectionProfiles
{
get
{
var networkInterfaceList = NetworkInformation.GetConnectionProfiles();
foreach (var interfaceInfo in networkInterfaceList.Where(nii => nii.GetNetworkConnectivityLevel() != NetworkConnectivityLevel.None))
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var nic in networkInterfaces)
{
var type = ConnectionProfile.Unknown;

try
if (nic.OperationalStatus is not OperationalStatus.Up ||
nic.NetworkInterfaceType is NetworkInterfaceType.Loopback ||
nic.NetworkInterfaceType is NetworkInterfaceType.Tunnel)
{
var adapter = interfaceInfo.NetworkAdapter;
if (adapter == null)
continue;

// http://www.iana.org/assignments/ianaiftype-mib/ianaiftype-mib
switch (adapter.IanaInterfaceType)
{
case 6:
type = ConnectionProfile.Ethernet;
break;
case 71:
type = ConnectionProfile.WiFi;
break;
case 243:
case 244:
type = ConnectionProfile.Cellular;
break;

// xbox wireless, can skip
case 281:
continue;
}
continue;
}
catch (Exception ex)

var interfaceType = ConnectionProfile.Unknown;
switch (nic.NetworkInterfaceType)
{
// TODO Add Logging?
Debug.WriteLine($"Unable to get Network Adapter, returning Unknown: {ex.Message}");
case NetworkInterfaceType.Ethernet:
interfaceType = ConnectionProfile.Ethernet;
break;
case NetworkInterfaceType.Wireless80211:
interfaceType = ConnectionProfile.WiFi;
break;
case NetworkInterfaceType.Wwanpp:
case NetworkInterfaceType.Wwanpp2:
interfaceType = ConnectionProfile.Cellular;
break;
}

yield return type;
yield return interfaceType;
}
}
}
Expand Down
Loading