Restore dual mail and calendar app entries
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Wino.Mail.WinUI.Helpers;
|
||||
|
||||
internal static class WindowAppUserModelIdHelper
|
||||
{
|
||||
private static readonly Guid PropertyStoreGuid = new("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99");
|
||||
private static readonly PropertyKey AppUserModelIdPropertyKey = new(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);
|
||||
|
||||
public static void TrySet(WindowEx window, string appUserModelId)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(window);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(appUserModelId))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
|
||||
if (hwnd == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
var propertyStoreGuid = PropertyStoreGuid;
|
||||
var appUserModelIdPropertyKey = AppUserModelIdPropertyKey;
|
||||
var hr = SHGetPropertyStoreForWindow(hwnd, ref propertyStoreGuid, out var propertyStore);
|
||||
if (hr < 0 || propertyStore == null)
|
||||
return;
|
||||
|
||||
using (propertyStore)
|
||||
{
|
||||
using var value = PropVariant.FromString(appUserModelId);
|
||||
propertyStore.SetValue(ref appUserModelIdPropertyKey, value);
|
||||
propertyStore.Commit();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Best effort only. Some Windows builds may keep the original taskbar identity.
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("shell32.dll")]
|
||||
private static extern int SHGetPropertyStoreForWindow(
|
||||
IntPtr hwnd,
|
||||
ref Guid riid,
|
||||
[MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
private readonly struct PropertyKey(Guid fmtid, uint pid)
|
||||
{
|
||||
public Guid FormatId { get; } = fmtid;
|
||||
public uint PropertyId { get; } = pid;
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IPropertyStore : IDisposable
|
||||
{
|
||||
uint GetCount();
|
||||
void GetAt(uint propertyIndex, out PropertyKey key);
|
||||
void GetValue(ref PropertyKey key, out PropVariant pv);
|
||||
void SetValue(ref PropertyKey key, PropVariant pv);
|
||||
void Commit();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private sealed class PropVariant : IDisposable
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
private ushort _valueType;
|
||||
|
||||
[FieldOffset(8)]
|
||||
private IntPtr _pointerValue;
|
||||
|
||||
private PropVariant(string value)
|
||||
{
|
||||
_valueType = 31;
|
||||
_pointerValue = Marshal.StringToCoTaskMemUni(value);
|
||||
}
|
||||
|
||||
public static PropVariant FromString(string value) => new(value);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PropVariantClear(this);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~PropVariant()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
[DllImport("ole32.dll")]
|
||||
private static extern int PropVariantClear([In, Out] PropVariant propvar);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user