Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/UniGetUI.Core.Logger/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ namespace UniGetUI.Core.Logging
public static class Logger
{
private static readonly List<LogEntry> LogContents = [];
private static readonly Lock LogWriteLock = new();
private static readonly string SessionLogPath = Path.Combine(
Path.GetTempPath(),
"UniGetUI",
"session.log"
);

public static string GetSessionLogPath() => SessionLogPath;

private static void AppendToSessionLog(string text)
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(SessionLogPath)!);
lock (LogWriteLock)
{
File.AppendAllText(
SessionLogPath,
$"[{DateTime.Now:yyyy-MM-dd h:mm:ss tt}] {text}{Environment.NewLine}"
);
}
}
catch { }
}

// String parameter log functions
public static void ImportantInfo(
Expand All @@ -13,6 +37,7 @@ public static void ImportantInfo(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + s);
AppendToSessionLog(s);
LogContents.Add(new LogEntry(s, LogEntry.SeverityLevel.Success));
}

Expand All @@ -22,6 +47,7 @@ public static void Debug(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + s);
AppendToSessionLog(s);
LogContents.Add(new LogEntry(s, LogEntry.SeverityLevel.Debug));
}

Expand All @@ -31,6 +57,7 @@ public static void Info(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + s);
AppendToSessionLog(s);
LogContents.Add(new LogEntry(s, LogEntry.SeverityLevel.Info));
}

Expand All @@ -40,6 +67,7 @@ public static void Warn(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + s);
AppendToSessionLog(s);
LogContents.Add(new LogEntry(s, LogEntry.SeverityLevel.Warning));
}

Expand All @@ -49,6 +77,7 @@ public static void Error(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + s);
AppendToSessionLog(s);
LogContents.Add(new LogEntry(s, LogEntry.SeverityLevel.Error));
}

Expand All @@ -59,6 +88,7 @@ public static void ImportantInfo(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + e.ToString());
AppendToSessionLog(e.ToString());
LogContents.Add(new LogEntry(e.ToString(), LogEntry.SeverityLevel.Success));
}

Expand All @@ -68,6 +98,7 @@ public static void Debug(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + e.ToString());
AppendToSessionLog(e.ToString());
LogContents.Add(new LogEntry(e.ToString(), LogEntry.SeverityLevel.Debug));
}

Expand All @@ -77,6 +108,7 @@ public static void Info(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + e.ToString());
AppendToSessionLog(e.ToString());
LogContents.Add(new LogEntry(e.ToString(), LogEntry.SeverityLevel.Info));
}

Expand All @@ -86,6 +118,7 @@ public static void Warn(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + e.ToString());
AppendToSessionLog(e.ToString());
LogContents.Add(new LogEntry(e.ToString(), LogEntry.SeverityLevel.Warning));
}

Expand All @@ -95,6 +128,7 @@ public static void Error(
)
{
Diagnostics.Debug.WriteLine($"[{caller}] " + e.ToString());
AppendToSessionLog(e.ToString());
LogContents.Add(new LogEntry(e.ToString(), LogEntry.SeverityLevel.Error));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ namespace UniGetUI.PackageEngine.Managers.WingetManager;

internal sealed class NativeWinGetHelper : IWinGetManagerHelper
{
public WindowsPackageManagerFactory Factory;
public WindowsPackageManagerFactory Factory = null!;
public static WindowsPackageManagerFactory? ExternalFactory;
public PackageManager WinGetManager;
public PackageManager WinGetManager = null!;
public static PackageManager? ExternalWinGetManager;
private readonly WinGet Manager;

public string ActivationMode { get; private set; } = string.Empty;
public string ActivationSource { get; private set; } = string.Empty;

public NativeWinGetHelper(WinGet manager)
{
Manager = manager;
Expand All @@ -32,25 +35,113 @@ public NativeWinGetHelper(WinGet manager)
);
}

if (TryInitializeBundledFactory())
{
return;
}

if (TryInitializeStandardFactory())
{
return;
}

InitializeLowerTrustFactory();
}

private bool TryInitializeBundledFactory()
{
try
{
Factory = new WindowsPackageManagerStandardFactory();
WinGetManager = Factory.CreatePackageManager();
ExternalFactory = Factory;
ExternalWinGetManager = WinGetManager;
var factory = new WindowsPackageManagerBundledFactory();
var winGetManager = factory.CreatePackageManager();
ApplyFactory(
factory,
winGetManager,
"bundled in-proc COM",
factory.LibraryPath,
"Connected to WinGet API using bundled in-proc activation."
);
return true;
}
catch (WinGetComActivationException ex)
{
Logger.Warn(
$"Bundled WinGet in-proc activation failed ({ex.HResultHex}: {ex.Reason}), attempting packaged COM activation..."
);
return false;
}
catch
catch (Exception ex)
{
Logger.Warn(
"Couldn't connect to WinGet API, attempting to connect with lower trust... (Are you running as administrator?)"
$"Bundled WinGet in-proc activation failed ({ex.Message}), attempting packaged COM activation..."
);
Factory = new WindowsPackageManagerStandardFactory(allowLowerTrustRegistration: true);
WinGetManager = Factory.CreatePackageManager();
ExternalFactory = Factory;
ExternalWinGetManager = WinGetManager;
return false;
}
}

private bool TryInitializeStandardFactory()
{
try
{
var factory = new WindowsPackageManagerStandardFactory();
var winGetManager = factory.CreatePackageManager();
ApplyFactory(
factory,
winGetManager,
"packaged COM registration",
"system COM registration",
"Connected to WinGet API using packaged COM activation."
);
return true;
}
catch (WinGetComActivationException ex)
{
Logger.Warn(
$"Packaged WinGet COM activation failed ({ex.HResultHex}: {ex.Reason}), attempting lower-trust activation..."
);
return false;
}
catch (Exception ex)
{
Logger.Warn(
$"Packaged WinGet COM activation failed ({ex.Message}), attempting lower-trust activation..."
);
return false;
}
}

private void InitializeLowerTrustFactory()
{
var factory = new WindowsPackageManagerStandardFactory(allowLowerTrustRegistration: true);
var winGetManager = factory.CreatePackageManager();
ApplyFactory(
factory,
winGetManager,
"lower-trust COM registration",
"system COM registration (allow lower trust)",
"Connected to WinGet API using lower-trust COM activation."
);
}

private void ApplyFactory(
WindowsPackageManagerFactory factory,
PackageManager winGetManager,
string activationMode,
string activationSource,
string successMessage
)
{
Factory = factory;
WinGetManager = winGetManager;
ActivationMode = activationMode;
ActivationSource = activationSource;
ExternalFactory = factory;
ExternalWinGetManager = winGetManager;

Logger.Info(successMessage);
Logger.Info($"WinGet activation mode selected: {ActivationMode} | Source: {ActivationSource}");
}

public IReadOnlyList<Package> FindPackages_UnSafe(string query)
{
List<Package> packages = [];
Expand Down
31 changes: 27 additions & 4 deletions src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using UniGetUI.PackageEngine.ManagerClasses.Classes;
using UniGetUI.PackageEngine.ManagerClasses.Manager;
using UniGetUI.PackageEngine.PackageClasses;
using WindowsPackageManager.Interop;
using Architecture = UniGetUI.PackageEngine.Enums.Architecture;

namespace UniGetUI.PackageEngine.Managers.WingetManager
Expand Down Expand Up @@ -319,10 +320,24 @@ out string callArguments
}
catch (Exception ex)
{
Logger.Warn(
$"Cannot instantiate {(FORCE_BUNDLED ? "Bundled" : "Native")} WinGet Helper due to error: {ex.Message}"
);
Logger.Warn(ex);
if (
!FORCE_BUNDLED
&& ex is WinGetComActivationException activationEx
&& activationEx.IsExpectedFallbackCondition
)
{
Logger.Warn(
$"Native WinGet helper is unavailable on this machine ({activationEx.HResultHex}: {activationEx.Reason})"
);
}
else
{
Logger.Warn(
$"Cannot instantiate {(FORCE_BUNDLED ? "Bundled" : "Native")} WinGet Helper due to error: {ex.Message}"
);
Logger.Warn(ex);
}

Logger.Warn("WinGet will resort to using BundledWinGetHelper()");
WinGetHelper.Instance = new BundledWinGetHelper(this);
}
Expand Down Expand Up @@ -361,8 +376,16 @@ protected override void _loadManagerVersion(out string version)
if (IS_BUNDLED)
version += "\nUsing bundled WinGet helper (CLI parsing)";
else
{
version += "\nUsing Native WinGet helper (COM Api)";

if (WinGetHelper.Instance is NativeWinGetHelper nativeHelper)
{
version += $"\nActivation mode: {nativeHelper.ActivationMode}";
version += $"\nActivation source: {nativeHelper.ActivationSource}";
}
}

string error = process.StandardError.ReadToEnd();
if (error != "")
Logger.Error("WinGet STDERR not empty: " + error);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Runtime.InteropServices;

namespace WindowsPackageManager.Interop;

public sealed class WinGetComActivationException : COMException
{
public Guid Clsid { get; }
public Guid Iid { get; }
public bool AllowLowerTrustRegistration { get; }
public string HResultHex => $"0x{HResult:X8}";

public string Reason => DescribeHResult(HResult);

public bool IsExpectedFallbackCondition =>
HResult is
unchecked((int)0x80040154) or
unchecked((int)0x80070490) or
unchecked((int)0x80070002) or
unchecked((int)0x8000000F)
|| Message.Contains("Element not found", StringComparison.OrdinalIgnoreCase)
|| Message.Contains(
"Typename or Namespace was not found in metadata file",
StringComparison.OrdinalIgnoreCase
);

public WinGetComActivationException(
Guid clsid,
Guid iid,
int hresult,
bool allowLowerTrustRegistration
)
: base(CreateMessage(clsid, iid, hresult, allowLowerTrustRegistration), hresult)
{
Clsid = clsid;
Iid = iid;
AllowLowerTrustRegistration = allowLowerTrustRegistration;
}

private static string CreateMessage(
Guid clsid,
Guid iid,
int hresult,
bool allowLowerTrustRegistration
) =>
$"WinGet COM activation failed for CLSID {clsid} (IID {iid}, AllowLowerTrustRegistration={allowLowerTrustRegistration}): {DescribeHResult(hresult)}";

private static string DescribeHResult(int hresult) => hresult switch
{
unchecked((int)0x80040154) => "Class not registered",
unchecked((int)0x80070490) => "Element not found",
unchecked((int)0x80070002) => "File not found",
unchecked((int)0x8000000F) => "Typename or Namespace was not found in metadata file",
_ => Marshal.GetExceptionForHR(hresult)?.Message ?? $"HRESULT 0x{hresult:X8}",
};
}
Loading