Search code examples
c#wifi.net-7.0

NetworkAdapter.GetConnectedProfile Threading Requirements


I am attempting to manage wifi stuff in my app and need to get the profile for the currently connected network. To the best of my knowledge the code is correct, but I am getting an threading error.

I have verified that this is executing on thread 1. This is the only code in the app that accesses these apis. I don't know what thread it's expecting me execute this on.

This is a WPF app using winRT libraries.

The error:

The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))

The code:

var access = await WiFiAdapter.RequestAccessAsync();
if (access != WiFiAccessStatus.Allowed) { Networks = new List<WiFiAvailableNetwork>(); return; }

var adapters = await WiFiAdapter.FindAllAdaptersAsync();
if (!adapters.Any()) return;

Adapter = adapters.First();
await Adapter.ScanAsync();
Networks = Adapter.NetworkReport.AvailableNetworks;

IReadOnlyList<ConnectionProfile> profiles = Array.Empty<ConnectionProfile>();
Application.Current.Dispatcher.Invoke(() => profiles = NetworkInformation.GetConnectionProfiles());
ConnectionProfiles = profiles;

ConnectionProfile profile = default;
try { profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync(); } // <= fails here
catch (Exception ex) { Log.Exception(ex); }

I have also tried the two alternatives below and they fail with the same error.

await Application.Current.Dispatcher.Invoke(async () => profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync());
await Application.Current.Dispatcher.InvokeAsync(async () => profile = await Adapter.NetworkAdapter.GetConnectedProfileAsync());

Solution

  • These objects and methods use COM calls, which are normally not thread-safe. Just putting NetworkInformation.GetConnectionProfiles() into an Invoke is not enough, the whole access to the objects returned must be on the same thread.

    So either put the whole function into Application.Current.Dispatcher.Invoke or alternatively remove that from NetworkInformation.GetConnectionProfiles().