Skip to content

Commit

Permalink
[WinUI] Add workaround for Connectivity check on Win10 (#19261)
Browse files Browse the repository at this point in the history
* Implemented a Win10 work-around for connectivity thread issue

Reimplement `ConnectivityImplementation.ConnectionProfiles` to use native .net core APIs

* Remove prop bag ID

* Replace network availability changed event with native .net API

* Remove explicit file include

* Fix file naming

* Implemented a Win10 work-around for connectivity thread issue

Reimplement `ConnectivityImplementation.ConnectionProfiles` to use native .net core APIs

* Remove prop bag ID

* Replace network availability changed event with native .net API

* Remove explicit file include

* Fix file naming

* * Revert change to remove `Windows.Networking.Connectivity.NetworkInformation.NetworkStatusChanged`

* Update Connectivity.uwp.cs

---------

Co-authored-by: Mike Corsaro <mikecorsaro@microsoft.com>
Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
  • Loading branch information
3 people authored Jan 23, 2024
1 parent e9029d0 commit 8c04a9d
Show file tree
Hide file tree
Showing 2 changed files with 240 additions and 43 deletions.
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

0 comments on commit 8c04a9d

Please sign in to comment.