Windows-Auto-Night-Mode
Windows-Auto-Night-Mode copied to clipboard
Migrate from Bing Maps to Azure Maps
Migrate from Bing Maps to Azure Maps:
- https://learn.microsoft.com/azure/azure-maps/migrate-bing-maps-overview
These APIs are deprecated. They are not likely to get fixed and you're not likely to get any support for them. Time to find an alternative I'm afraid.
- source: https://github.com/microsoft/microsoft-ui-xaml/issues/10229#issuecomment-2540275280
[!IMPORTANT] Important
Bing Maps for Enterprise service retirement
The UWP MapControl and map services from the Windows.Services.Maps namespaces rely on Bing Maps. Bing Maps for Enterprise is deprecated and will be retired, at which point the MapControl and services will no longer receive data.
For more information, see the Bing Maps Developer Center and Bing Maps documentation.
https://learn.microsoft.com/en-us/uwp/api/windows.services.maps?view=winrt-26100#remarks
I copied "Azure" from the comment(s), but if there's another simple server, that's also fine with me, of course.
Today, Copilot gave me a few very simple PowerShell suggestions:
Since you want automatic location detection in the background, we’ll tap into Windows’ built-in geolocation capabilities using PowerShell. Here's a clean and relatively lightweight approach:
🧭 Step 1: Automatically Fetch Location (Lat/Lon)
Windows exposes location data via the System.Device.Location namespace. You can access it in PowerShell like this:
Add-Type -AssemblyName System.Device
$GeoWatcher = New-Object System.Device.Location.GeoCoordinateWatcher
$GeoWatcher.Start()
while (($GeoWatcher.Status -ne 'Ready') -and ($GeoWatcher.Permission -ne 'Denied')) {
Start-Sleep -Milliseconds 100
}
if ($GeoWatcher.Permission -eq 'Denied') {
Write-Error 'Access Denied for Location Information'
} else {
$location = $GeoWatcher.Position.Location
$latitude = $location.Latitude
$longitude = $location.Longitude
Write-Output "Latitude: $latitude, Longitude: $longitude"
}
✅ This script runs silently and fetches your current coordinates. Make sure location services are enabled in Windows Settings → Privacy → Location.
🌅 Step 2: Get Sunrise/Sunset Times
Use the Sunrise-Sunset API — it’s free and doesn’t require an API key. Here’s how to query it:
$apiUrl = "https://api.sunrise-sunset.org/json?lat=$latitude&lng=$longitude&formatted=0"
$response = Invoke-RestMethod -Uri $apiUrl
$sunriseUTC = [datetime]$response.results.sunrise
$sunsetUTC = [datetime]$response.results.sunset
# Convert to local time
$sunriseLocal = $sunriseUTC.ToLocalTime()
$sunsetLocal = $sunsetUTC.ToLocalTime()
Write-Output "Sunrise: $sunriseLocal"
Write-Output "Sunset: $sunsetLocal"
🎨 Step 3: Switch Windows Theme Based on Time
You can toggle between light and dark modes by editing the registry and restarting explorer.exe. Here’s a basic example:
function Set-DarkMode {
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Name "AppsUseLightTheme" -Value 0
Stop-Process -Name explorer -Force
Start-Process explorer.exe
}
function Set-LightMode {
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Name "AppsUseLightTheme" -Value 1
Stop-Process -Name explorer -Force
Start-Process explorer.exe
}
$currentTime = Get-Date
if ($currentTime -gt $sunriseLocal -and $currentTime -lt $sunsetLocal) {
Set-LightMode
} else {
Set-DarkMode
}
🕒 Step 4: Automate It
Use Task Scheduler to run this script every hour or at login. You can compile it into a .ps1 file and schedule it with highest privileges.
And for C# code:
let’s build a C# console app that:
- Automatically fetches your geolocation (latitude/longitude)
- Queries the Sunrise-Sunset API
- Compares current time to sunrise/sunset
- Switches Windows theme accordingly
🧠 Key Notes Before We Dive In
• Geolocation: Windows doesn’t expose location via .NET directly, so we’ll use IP-based geolocation via a free API like ip-api.com.
• Theme Switching: We’ll modify the registry and restart explorer.exe to apply the theme.
• Scheduling: You can run this app periodically via Task Scheduler.
💻 Full C# Console App
using System;
using System.Net.Http;
using System.Text.Json;
using Microsoft.Win32;
using System.Diagnostics;
class Program
{
static async System.Threading.Tasks.Task Main()
{
var client = new HttpClient();
// Step 1: Get location via IP
var geoResponse = await client.GetStringAsync("http://ip-api.com/json/");
var geoData = JsonDocument.Parse(geoResponse).RootElement;
double lat = geoData.GetProperty("lat").GetDouble();
double lon = geoData.GetProperty("lon").GetDouble();
// Step 2: Get sunrise/sunset times
string apiUrl = $"https://api.sunrise-sunset.org/json?lat={lat}&lng={lon}&formatted=0";
var sunResponse = await client.GetStringAsync(apiUrl);
var sunData = JsonDocument.Parse(sunResponse).RootElement.GetProperty("results");
DateTime sunriseUtc = DateTime.Parse(sunData.GetProperty("sunrise").GetString());
DateTime sunsetUtc = DateTime.Parse(sunData.GetProperty("sunset").GetString());
DateTime sunriseLocal = sunriseUtc.ToLocalTime();
DateTime sunsetLocal = sunsetUtc.ToLocalTime();
DateTime now = DateTime.Now;
Console.WriteLine($"Sunrise: {sunriseLocal}, Sunset: {sunsetLocal}, Now: {now}");
// Step 3: Switch theme
bool isDaytime = now > sunriseLocal && now < sunsetLocal;
SetTheme(isDaytime);
}
static void SetTheme(bool useLight)
{
const string personalizeKey = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(personalizeKey, true))
{
if (key != null)
{
key.SetValue("AppsUseLightTheme", useLight ? 1 : 0, RegistryValueKind.DWord);
key.SetValue("SystemUsesLightTheme", useLight ? 1 : 0, RegistryValueKind.DWord);
}
}
// Restart explorer to apply changes
foreach (var process in Process.GetProcessesByName("explorer"))
{
process.Kill();
}
Process.Start("explorer.exe");
}
}
🛠️ How to Use
- Compile with .NET (e.g.,
dotnet build) - Run manually or schedule via Task Scheduler
- Make sure location services are enabled, or IP-based geolocation is acceptable
✅ Safer Alternatives
If you want to avoid killing explorer.exe, here are gentler options:
- Use
SendMessageTimeoutto broadcast a settings change This can sometimes trigger a UI refresh without restarting Explorer:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam,
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
const uint WM_SETTINGCHANGE = 0x001A;
const uint SMTO_ABORTIFHUNG = 0x0002;
SendMessageTimeout(new IntPtr(0xffff), WM_SETTINGCHANGE, UIntPtr.Zero, IntPtr.Zero,
SMTO_ABORTIFHUNG, 100, out _);
- Prompt the user to log out or restart manually
- Display a message box explaining the change and asking for confirmation before restarting Explorer
Couple of points from the linked wiki:
Your app must be authenticated before it can use the MapControl and map services in the Windows.Services.Maps namespace. To authenticate your app, you must specify a maps authentication key.
@Armin2208 We never acquired such an authentication key, right? Strange that it had worked before for many years.
@Jay-o-Way Concerning the deprecation of the Maps API and the UWP controls:
For the backend lat/lon calculation, we use Windows.Devices.Geolocation. This one is not deprecated and does not rely on an external maps service. It's part of the OS geolocation functionality.
As such, the migration we're talking about here is really just about displaying the city name in the UI.
It appears that using Azure Maps is not an option, it requires us to provision an Azure or Bing Maps API key. https://learn.microsoft.com/en-us/azure/azure-maps/migrate-find-location-by-point If we don't find a good alternative to it, my suggestion would just be to display the retrieved Lat/Lon values in auto gelocation mode.
UPDATE: I've pulled a newer geojson version, and we now have country-level translation!
Location Mapping is now done offline via a GIS database.
The GIS database comes with the downside that names aren't translated (I'm using the GeoJSON version due to deserialization issues with .dbf files).
But it's a better solution that nothing, is completely free, the Natural Earth database is very permissive with allowed redistribution, and it's fast!