diff --git a/dnSpy/dnSpy.Contracts.DnSpy/App/IAppCommandLineArgs.cs b/dnSpy/dnSpy.Contracts.DnSpy/App/IAppCommandLineArgs.cs
index 8856620532..f4e044d430 100644
--- a/dnSpy/dnSpy.Contracts.DnSpy/App/IAppCommandLineArgs.cs
+++ b/dnSpy/dnSpy.Contracts.DnSpy/App/IAppCommandLineArgs.cs
@@ -90,6 +90,9 @@ public interface IAppCommandLineArgs {
/// Attach to this process name, unless it's empty. Can contain wildcards.
string DebugAttachProcess { get; }
+ /// Additional directory to check for extensions.
+ string ExtraExtensionDirectory { get; }
+
///
/// Returns true if the argument is present
///
diff --git a/dnSpy/dnSpy/MainApp/App.xaml.cs b/dnSpy/dnSpy/MainApp/App.xaml.cs
index d5944f86a9..d6773e6c28 100644
--- a/dnSpy/dnSpy/MainApp/App.xaml.cs
+++ b/dnSpy/dnSpy/MainApp/App.xaml.cs
@@ -96,6 +96,7 @@ static void ShowException(Exception? ex) {
Stopwatch? startupStopwatch;
public App(bool readSettings, Stopwatch startupStopwatch) {
resourceManagerTokenCacheImpl = new ResourceManagerTokenCacheImpl();
+ args = new AppCommandLineArgs();
// PERF: Init MEF on a BG thread. Results in slightly faster startup, eg. InitializeComponent() becomes a 'free' call on this UI thread
initializeMEFTask = Task.Run(() => InitializeMEF(readSettings, useCache: readSettings));
@@ -103,7 +104,6 @@ public App(bool readSettings, Stopwatch startupStopwatch) {
resourceManagerTokenCacheImpl.TokensUpdated += ResourceManagerTokenCacheImpl_TokensUpdated;
ResourceHelper.SetResourceManagerTokenCache(resourceManagerTokenCacheImpl);
- args = new AppCommandLineArgs();
AppDirectories.SetSettingsFilename(args.SettingsFilename);
AddAppContextFixes();
@@ -324,10 +324,14 @@ Assembly[] GetAssemblies() {
Assembly[] LoadExtensionAssemblies() {
var dir = AppDirectories.BinDirectory;
+ var unsortedFiles = GetExtensionFiles(dir);
+ if (!(args.ExtraExtensionDirectory is null))
+ unsortedFiles = unsortedFiles.Concat(GetExtensionFiles(args.ExtraExtensionDirectory));
+
// Load the modules in a predictable order or multicore-JIT could stop recording. See
// "Understanding Background JIT compilation -> What can go wrong with background JIT compilation"
// in the PerfView docs for more info.
- var files = GetExtensionFiles(dir).OrderBy(a => a, StringComparer.OrdinalIgnoreCase).ToArray();
+ var files = unsortedFiles.OrderBy(a => a, StringComparer.OrdinalIgnoreCase).ToArray();
#if NETCOREAPP
foreach (var file in files)
netCoreAssemblyLoader.AddSearchPath(Path.GetDirectoryName(file)!);
diff --git a/dnSpy/dnSpy/MainApp/AppCommandLineArgs.cs b/dnSpy/dnSpy/MainApp/AppCommandLineArgs.cs
index 87c55e41a8..47a8e15999 100644
--- a/dnSpy/dnSpy/MainApp/AppCommandLineArgs.cs
+++ b/dnSpy/dnSpy/MainApp/AppCommandLineArgs.cs
@@ -49,6 +49,7 @@ sealed class AppCommandLineArgs : IAppCommandLineArgs {
public uint DebugEvent { get; }
public ulong JitDebugInfo { get; }
public string DebugAttachProcess { get; }
+ public string ExtraExtensionDirectory { get; }
readonly Dictionary userArgs = new Dictionary();
readonly List filenames = new List();
@@ -194,6 +195,11 @@ public AppCommandLineArgs(string[] args) {
i++;
break;
+ case "--extension-directory":
+ ExtraExtensionDirectory = GetFullPath(next);
+ i++;
+ break;
+
default:
int sepIndex = arg.IndexOf(ARG_SEP);
string argName, argValue;