using System.Runtime.InteropServices;
namespace SwyxTray;
internal static class NativeMethods
{
///
/// Gibt ein von erzeugtes
/// HICON frei. Ohne diesen Aufruf leckt jedes erzeugte Symbol ein
/// GDI-Handle.
///
/// Bewusst DllImport statt LibraryImport: Letzteres verlangt
/// AllowUnsafeBlocks fuer das gesamte Projekt, was fuer diesen einen
/// Aufruf unverhaeltnismaessig waere.
///
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DestroyIcon(IntPtr hIcon);
private const uint RpcCAuthnLevelNone = 1;
private const uint RpcCImpLevelIdentify = 2;
private const uint EoacNone = 0;
/// Wurde zu spaet aufgerufen — COM war bereits gemarshallt.
private const int RpcETooLate = unchecked((int)0x80010119);
[DllImport("ole32.dll")]
private static extern int CoInitializeEx(IntPtr pvReserved, uint dwCoInit);
[DllImport("ole32.dll")]
private static extern int CoInitializeSecurity(
IntPtr pSecDesc, int cAuthSvc, IntPtr asAuthSvc, IntPtr pReserved1,
uint dwAuthnLevel, uint dwImpLevel, IntPtr pAuthList,
uint dwCapabilities, IntPtr pReserved3);
///
/// Erlaubt CLMgr, Ereignisse in diesen Prozess zurueckzurufen.
///
/// CLMgr.exe ist ein eigener Prozess. Beim Anmelden der Ereignissenke
/// (IConnectionPoint::Advise) ruft CLMgr in unseren Prozess zurueck.
/// Ohne eigene Sicherheitsvorgabe verwendet COM Standardwerte, unter denen
/// dieser Rueckruf mit E_ACCESSDENIED abgewiesen wird.
///
/// Authentifizierungsstufe NONE bedeutet: eingehende COM-Aufrufe an diesen
/// Prozess werden nicht authentifiziert. Das ist die uebliche Einstellung
/// fuer COM-Ereignissenken und betrifft nur diesen Prozess, der ausser der
/// Senke keine Schnittstellen nach aussen anbietet. Wer es enger fassen
/// will, probiert RPC_C_AUTHN_LEVEL_CONNECT (2) — das genuegt, solange
/// CLMgr in derselben Sitzung und unter demselben Konto laeuft.
///
/// Muss vor dem ersten COM-Aufruf erfolgen; danach liefert Windows
/// RPC_E_TOO_LATE.
///
/// HRESULT des Aufrufs, 0 = Erfolg.
internal static int InitializeComSecurity()
{
// Das Apartment steht durch [STAThread] fest; dieser Aufruf stellt nur
// sicher, dass COM initialisiert ist, bevor die Sicherheit gesetzt wird.
const uint coinitApartmentThreaded = 0x2;
CoInitializeEx(IntPtr.Zero, coinitApartmentThreaded);
return CoInitializeSecurity(
IntPtr.Zero, -1, IntPtr.Zero, IntPtr.Zero,
RpcCAuthnLevelNone, RpcCImpLevelIdentify, IntPtr.Zero,
EoacNone, IntPtr.Zero);
}
internal static bool IsTooLate(int hresult) => hresult == RpcETooLate;
}