Browse Source

Merge pull request #3205 from icsharpcode/feature/atfile

`@file` support with breaking changes to command line options
pull/3215/head
Siegfried Pammer 2 years ago committed by GitHub
parent
commit
d7771486d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      Directory.Packages.props
  2. 2
      ILSpy.AddIn.Shared/Commands/OpenCodeItemCommand.cs
  3. 18
      ILSpy.AddIn.Shared/ILSpyAddInPackage.cs
  4. 94
      ILSpy.AddIn.Shared/ILSpyInstance.cs
  5. 1
      ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj
  6. 1
      ILSpy.AddIn/ILSpy.AddIn.csproj
  7. 123
      ILSpy.Tests/CommandLineArgumentsTests.cs
  8. 1
      ILSpy.Tests/ILSpy.Tests.csproj
  9. 11
      ILSpy/App.xaml.cs
  10. 91
      ILSpy/CommandLineArguments.cs
  11. 2
      ILSpy/ILSpy.csproj
  12. 6
      ILSpy/Properties/launchSettings.json
  13. 6
      ILSpy/SingleInstanceHandling.cs
  14. 71
      doc/Command Line.txt
  15. 13
      publishlocaldev.ps1

1
Directory.Packages.props

@ -14,6 +14,7 @@
<PackageVersion Include="Iced" Version="1.21.0" /> <PackageVersion Include="Iced" Version="1.21.0" />
<PackageVersion Include="JunitXml.TestLogger" Version="3.1.12" /> <PackageVersion Include="JunitXml.TestLogger" Version="3.1.12" />
<PackageVersion Include="K4os.Compression.LZ4" Version="1.3.8" /> <PackageVersion Include="K4os.Compression.LZ4" Version="1.3.8" />
<PackageVersion Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageVersion Include="McMaster.Extensions.Hosting.CommandLine" Version="4.1.1" /> <PackageVersion Include="McMaster.Extensions.Hosting.CommandLine" Version="4.1.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.9.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.9.2" />

2
ILSpy.AddIn.Shared/Commands/OpenCodeItemCommand.cs

@ -140,7 +140,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
return; return;
} }
OpenAssembliesInILSpy(new ILSpyParameters(validRefs.Select(r => r.AssemblyFile), "/navigateTo:" + OpenAssembliesInILSpy(new ILSpyParameters(validRefs.Select(r => r.AssemblyFile), "--navigateto:" +
(symbol.OriginalDefinition ?? symbol).GetDocumentationCommentId())); (symbol.OriginalDefinition ?? symbol).GetDocumentationCommentId()));
} }

18
ILSpy.AddIn.Shared/ILSpyAddInPackage.cs

@ -97,6 +97,24 @@ namespace ICSharpCode.ILSpy.AddIn
OpenReferenceCommand.Register(this); OpenReferenceCommand.Register(this);
OpenCodeItemCommand.Register(this); OpenCodeItemCommand.Register(this);
} }
protected override int QueryClose(out bool canClose)
{
var tempFiles = ILSpyInstance.TempFiles;
while (tempFiles.TryPop(out var filename))
{
try
{
System.IO.File.Delete(filename);
}
catch (Exception)
{
}
}
return base.QueryClose(out canClose);
}
#endregion #endregion
public void ShowMessage(string format, params object[] items) public void ShowMessage(string format, params object[] items)

94
ILSpy.AddIn.Shared/ILSpyInstance.cs

@ -1,11 +1,9 @@
using System; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.ILSpy.AddIn namespace ICSharpCode.ILSpy.AddIn
{ {
@ -23,8 +21,9 @@ namespace ICSharpCode.ILSpy.AddIn
class ILSpyInstance class ILSpyInstance
{ {
readonly ILSpyParameters parameters; internal static readonly ConcurrentStack<string> TempFiles = new ConcurrentStack<string>();
readonly ILSpyParameters parameters;
public ILSpyInstance(ILSpyParameters parameters = null) public ILSpyInstance(ILSpyParameters parameters = null)
{ {
this.parameters = parameters; this.parameters = parameters;
@ -47,85 +46,30 @@ namespace ICSharpCode.ILSpy.AddIn
{ {
var commandLineArguments = parameters?.AssemblyFileNames?.Concat(parameters.Arguments); var commandLineArguments = parameters?.AssemblyFileNames?.Concat(parameters.Arguments);
string ilSpyExe = GetILSpyPath(); string ilSpyExe = GetILSpyPath();
var process = new Process() {
StartInfo = new ProcessStartInfo() {
FileName = ilSpyExe,
UseShellExecute = false,
Arguments = "/navigateTo:none"
}
};
process.Start();
if ((commandLineArguments != null) && commandLineArguments.Any()) const string defaultOptions = "--navigateto:none";
{ string argumentsToPass = defaultOptions;
// Only need a message to started process if there are any parameters to pass
SendMessage(ilSpyExe, "ILSpy:\r\n" + string.Join(Environment.NewLine, commandLineArguments), true);
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD110:Observe result of async calls", Justification = "<Pending>")] if ((commandLineArguments != null) && commandLineArguments.Any())
void SendMessage(string ilSpyExe, string message, bool activate)
{
string expectedProcessName = Path.GetFileNameWithoutExtension(ilSpyExe);
// We wait asynchronously until target window can be found and try to find it multiple times
Task.Run(async () => {
bool success = false;
int remainingAttempts = 20;
do
{
NativeMethods.EnumWindows(
(hWnd, lParam) => {
string windowTitle = NativeMethods.GetWindowText(hWnd, 100);
if (windowTitle.StartsWith("ILSpy", StringComparison.Ordinal))
{
string processName = NativeMethods.GetProcessNameFromWindow(hWnd);
Debug.WriteLine("Found {0:x4}: '{1}' in '{2}'", hWnd, windowTitle, processName);
if (string.Equals(processName, expectedProcessName, StringComparison.OrdinalIgnoreCase))
{
IntPtr result = Send(hWnd, message);
Debug.WriteLine("WM_COPYDATA result: {0:x8}", result);
if (result == (IntPtr)1)
{ {
if (activate) string assemblyArguments = string.Join("\r\n", commandLineArguments);
NativeMethods.SetForegroundWindow(hWnd);
success = true;
return false; // stop enumeration
}
}
}
return true; // continue enumeration
}, IntPtr.Zero);
// Wait some time before next attempt string filepath = Path.GetTempFileName();
await Task.Delay(500); File.WriteAllText(filepath, assemblyArguments);
remainingAttempts--;
} while (!success && (remainingAttempts > 0));
});
}
unsafe static IntPtr Send(IntPtr hWnd, string message) TempFiles.Push(filepath);
{
const uint SMTO_NORMAL = 0;
CopyDataStruct lParam; argumentsToPass = $"@\"{filepath}\"";
lParam.Padding = IntPtr.Zero;
lParam.Size = message.Length * 2;
fixed (char* buffer = message)
{
lParam.Buffer = (IntPtr)buffer;
IntPtr result;
// SendMessage with 3s timeout (e.g. when the target process is stopped in the debugger)
if (NativeMethods.SendMessageTimeout(
hWnd, NativeMethods.WM_COPYDATA, IntPtr.Zero, ref lParam,
SMTO_NORMAL, 3000, out result) != IntPtr.Zero)
{
return result;
}
else
{
return IntPtr.Zero;
} }
var process = new Process() {
StartInfo = new ProcessStartInfo() {
FileName = ilSpyExe,
UseShellExecute = false,
Arguments = argumentsToPass
} }
};
process.Start();
} }
} }
} }

1
ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj

@ -70,7 +70,6 @@
<Compile Include="..\ICSharpCode.Decompiler\Metadata\LightJson\Serialization\TextScanner.cs" Link="Decompiler\LightJson\Serialization\TextScanner.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Metadata\LightJson\Serialization\TextScanner.cs" Link="Decompiler\LightJson\Serialization\TextScanner.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Metadata\UniversalAssemblyResolver.cs" Link="UniversalAssemblyResolver.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Metadata\UniversalAssemblyResolver.cs" Link="UniversalAssemblyResolver.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Util\EmptyList.cs" Link="Decompiler\EmptyList.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Util\EmptyList.cs" Link="Decompiler\EmptyList.cs" />
<Compile Include="..\ILSpy\NativeMethods.cs" Link="NativeMethods.cs" />
<Compile Include="Decompiler\Dummy.cs" /> <Compile Include="Decompiler\Dummy.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

1
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -76,7 +76,6 @@
<Compile Include="..\ICSharpCode.Decompiler\Metadata\LightJson\Serialization\TextScanner.cs" Link="Decompiler\LightJson\Serialization\TextScanner.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Metadata\LightJson\Serialization\TextScanner.cs" Link="Decompiler\LightJson\Serialization\TextScanner.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Metadata\UniversalAssemblyResolver.cs" Link="UniversalAssemblyResolver.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Metadata\UniversalAssemblyResolver.cs" Link="UniversalAssemblyResolver.cs" />
<Compile Include="..\ICSharpCode.Decompiler\Util\EmptyList.cs" Link="Decompiler\EmptyList.cs" /> <Compile Include="..\ICSharpCode.Decompiler\Util\EmptyList.cs" Link="Decompiler\EmptyList.cs" />
<Compile Include="..\ILSpy\NativeMethods.cs" Link="NativeMethods.cs" />
<Compile Include="Decompiler\Dummy.cs" /> <Compile Include="Decompiler\Dummy.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

123
ILSpy.Tests/CommandLineArgumentsTests.cs

@ -0,0 +1,123 @@
using System;
using FluentAssertions;
using NUnit.Framework;
namespace ICSharpCode.ILSpy.Tests
{
[TestFixture]
public class CommandLineArgumentsTests
{
[Test]
public void VerifyEmptyArgumentsArray()
{
var cmdLineArgs = new CommandLineArguments(new string[] { });
cmdLineArgs.AssembliesToLoad.Should().BeEmpty();
cmdLineArgs.SingleInstance.Should().BeNull();
cmdLineArgs.NavigateTo.Should().BeNull();
cmdLineArgs.Search.Should().BeNull();
cmdLineArgs.Language.Should().BeNull();
cmdLineArgs.NoActivate.Should().BeFalse();
cmdLineArgs.ConfigFile.Should().BeNull();
}
[Test]
public void VerifyHelpOption()
{
var cmdLineArgs = new CommandLineArguments(new string[] { "--help" });
cmdLineArgs.ArgumentsParser.IsShowingInformation.Should().BeTrue();
}
[Test]
public void VerifyForceNewInstanceOption()
{
var cmdLineArgs = new CommandLineArguments(new string[] { "--newinstance" });
cmdLineArgs.SingleInstance.Should().BeFalse();
}
[Test]
public void VerifyNavigateToOption()
{
const string navigateTo = "MyNamespace.MyClass";
var cmdLineArgs = new CommandLineArguments(new string[] { "--navigateto", navigateTo });
cmdLineArgs.NavigateTo.Should().BeEquivalentTo(navigateTo);
}
[Test]
public void VerifyNavigateToOption_NoneTest_Matching_VSAddin()
{
var cmdLineArgs = new CommandLineArguments(new string[] { "--navigateto:none" });
cmdLineArgs.NavigateTo.Should().BeEquivalentTo("none");
}
[Test]
public void VerifyCaseSensitivityOfOptionsDoesntThrow()
{
var cmdLineArgs = new CommandLineArguments(new string[] { "--navigateTo:none" });
cmdLineArgs.ArgumentsParser.RemainingArguments.Should().HaveCount(1);
}
[Test]
public void VerifySearchOption()
{
const string searchWord = "TestContainers";
var cmdLineArgs = new CommandLineArguments(new string[] { "--search", searchWord });
cmdLineArgs.Search.Should().BeEquivalentTo(searchWord);
}
[Test]
public void VerifyLanguageOption()
{
const string language = "csharp";
var cmdLineArgs = new CommandLineArguments(new string[] { "--language", language });
cmdLineArgs.Language.Should().BeEquivalentTo(language);
}
[Test]
public void VerifyConfigOption()
{
const string configFile = "myilspyoptions.xml";
var cmdLineArgs = new CommandLineArguments(new string[] { "--config", configFile });
cmdLineArgs.ConfigFile.Should().BeEquivalentTo(configFile);
}
[Test]
public void VerifyNoActivateOption()
{
var cmdLineArgs = new CommandLineArguments(new string[] { "--noactivate" });
cmdLineArgs.NoActivate.Should().BeTrue();
}
[Test]
public void MultipleAssembliesAsArguments()
{
var cmdLineArgs = new CommandLineArguments(new string[] { "assembly1", "assembly2", "assembly3" });
cmdLineArgs.AssembliesToLoad.Should().HaveCount(3);
}
[Test]
public void PassAtFileArguments()
{
string filepath = System.IO.Path.GetTempFileName();
System.IO.File.WriteAllText(filepath, "assembly1\r\nassembly2\r\nassembly3\r\n--newinstance\r\n--noactivate");
var cmdLineArgs = new CommandLineArguments(new string[] { $"@{filepath}" });
try
{
System.IO.File.Delete(filepath);
}
catch (Exception)
{
}
cmdLineArgs.SingleInstance.Should().BeFalse();
cmdLineArgs.NoActivate.Should().BeTrue();
cmdLineArgs.AssembliesToLoad.Should().HaveCount(3);
}
}
}

1
ILSpy.Tests/ILSpy.Tests.csproj

@ -39,6 +39,7 @@
<Compile Include="Analyzers\MethodUsesAnalyzerTests.cs" /> <Compile Include="Analyzers\MethodUsesAnalyzerTests.cs" />
<Compile Include="Analyzers\TestCases\MainAssembly.cs" /> <Compile Include="Analyzers\TestCases\MainAssembly.cs" />
<Compile Include="Analyzers\TypeUsedByAnalyzerTests.cs" /> <Compile Include="Analyzers\TypeUsedByAnalyzerTests.cs" />
<Compile Include="CommandLineArgumentsTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

11
ILSpy/App.xaml.cs

@ -87,6 +87,17 @@ namespace ICSharpCode.ILSpy
Hyperlink.RequestNavigateEvent, Hyperlink.RequestNavigateEvent,
new RequestNavigateEventHandler(Window_RequestNavigate)); new RequestNavigateEventHandler(Window_RequestNavigate));
ILSpyTraceListener.Install(); ILSpyTraceListener.Install();
if (App.CommandLineArguments.ArgumentsParser.IsShowingInformation)
{
MessageBox.Show(App.CommandLineArguments.ArgumentsParser.GetHelpText(), "ILSpy Command Line Arguments");
}
if (App.CommandLineArguments.ArgumentsParser.RemainingArguments.Any())
{
string unknownArguments = string.Join(", ", App.CommandLineArguments.ArgumentsParser.RemainingArguments);
MessageBox.Show(unknownArguments, "ILSpy Unknown Command Line Arguments Passed");
}
} }
static Assembly ResolvePluginDependencies(AssemblyLoadContext context, AssemblyName assemblyName) static Assembly ResolvePluginDependencies(AssemblyLoadContext context, AssemblyName assemblyName)

91
ILSpy/CommandLineArguments.cs

@ -16,12 +16,14 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using McMaster.Extensions.CommandLineUtils;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
sealed class CommandLineArguments public sealed class CommandLineArguments
{ {
// see /doc/Command Line.txt for details // see /doc/Command Line.txt for details
public List<string> AssembliesToLoad = new List<string>(); public List<string> AssembliesToLoad = new List<string>();
@ -32,33 +34,70 @@ namespace ICSharpCode.ILSpy
public bool NoActivate; public bool NoActivate;
public string ConfigFile; public string ConfigFile;
public CommandLineApplication ArgumentsParser { get; }
public CommandLineArguments(IEnumerable<string> arguments) public CommandLineArguments(IEnumerable<string> arguments)
{ {
foreach (string arg in arguments) var app = new CommandLineApplication() {
{ // https://natemcmaster.github.io/CommandLineUtils/docs/response-file-parsing.html?tabs=using-attributes
if (arg.Length == 0) ResponseFileHandling = ResponseFileHandling.ParseArgsAsLineSeparated,
continue;
if (arg[0] == '/') // Note: options are case-sensitive (!), and, default behavior would be UnrecognizedArgumentHandling.Throw on Parse()
{ UnrecognizedArgumentHandling = UnrecognizedArgumentHandling.CollectAndContinue
if (arg.Equals("/singleInstance", StringComparison.OrdinalIgnoreCase)) };
this.SingleInstance = true;
else if (arg.Equals("/separate", StringComparison.OrdinalIgnoreCase)) app.HelpOption();
this.SingleInstance = false; ArgumentsParser = app;
else if (arg.StartsWith("/navigateTo:", StringComparison.OrdinalIgnoreCase))
this.NavigateTo = arg.Substring("/navigateTo:".Length); var oForceNewInstance = app.Option("--newinstance",
else if (arg.StartsWith("/search:", StringComparison.OrdinalIgnoreCase)) "Start a new instance of ILSpy even if the user configuration is set to single-instance",
this.Search = arg.Substring("/search:".Length); CommandOptionType.NoValue);
else if (arg.StartsWith("/language:", StringComparison.OrdinalIgnoreCase))
this.Language = arg.Substring("/language:".Length); var oNavigateTo = app.Option<string>("-n|--navigateto <TYPENAME>",
else if (arg.Equals("/noActivate", StringComparison.OrdinalIgnoreCase)) "Navigates to the member specified by the given ID string.\r\nThe member is searched for only in the assemblies specified on the command line.\r\nExample: 'ILSpy ILSpy.exe --navigateto:T:ICSharpCode.ILSpy.CommandLineArguments'",
this.NoActivate = true; CommandOptionType.SingleValue);
else if (arg.StartsWith("/config:", StringComparison.OrdinalIgnoreCase)) oNavigateTo.DefaultValue = null;
this.ConfigFile = arg.Substring("/config:".Length);
} var oSearch = app.Option<string>("-s|--search <SEARCHTERM>",
else "Search for t:TypeName, m:Member or c:Constant; use exact match (=term), 'should not contain' (-term) or 'must contain' (+term); use /reg(ular)?Ex(pressions)?/ or both - t:/Type(Name)?/...",
CommandOptionType.SingleValue);
oSearch.DefaultValue = null;
var oLanguage = app.Option<string>("-l|--language <LANGUAGEIDENTIFIER>",
"Selects the specified language.\r\nExample: 'ILSpy --language:C#' or 'ILSpy --language:IL'",
CommandOptionType.SingleValue);
oLanguage.DefaultValue = null;
var oConfig = app.Option<string>("-c|--config <CONFIGFILENAME>",
"Provide a specific configuration file.\r\nExample: 'ILSpy --config:myconfig.xml'",
CommandOptionType.SingleValue);
oConfig.DefaultValue = null;
var oNoActivate = app.Option("--noactivate",
"Do not activate the existing ILSpy instance. This option has no effect if a new ILSpy instance is being started.",
CommandOptionType.NoValue);
// https://natemcmaster.github.io/CommandLineUtils/docs/arguments.html#variable-numbers-of-arguments
// To enable this, MultipleValues must be set to true, and the argument must be the last one specified.
var files = app.Argument("Assemblies", "Assemblies to load", multipleValues: true);
app.Parse(arguments.ToArray());
if (oForceNewInstance.HasValue())
SingleInstance = false;
NavigateTo = oNavigateTo.ParsedValue;
Search = oSearch.ParsedValue;
Language = oLanguage.ParsedValue;
ConfigFile = oConfig.ParsedValue;
if (oNoActivate.HasValue())
NoActivate = true;
foreach (var assembly in files.Values)
{ {
this.AssembliesToLoad.Add(arg); if (!string.IsNullOrWhiteSpace(assembly))
} AssembliesToLoad.Add(assembly);
} }
} }
} }

2
ILSpy/ILSpy.csproj

@ -45,6 +45,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AvalonEdit" /> <PackageReference Include="AvalonEdit" />
<PackageReference Include="Dirkster.AvalonDock.Themes.VS2013" /> <PackageReference Include="Dirkster.AvalonDock.Themes.VS2013" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" />
<PackageReference Include="Microsoft.VisualStudio.Composition" /> <PackageReference Include="Microsoft.VisualStudio.Composition" />
<PackageReference Include="DataGridExtensions" /> <PackageReference Include="DataGridExtensions" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" /> <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
@ -65,7 +66,6 @@
<EmbeddedResource Include="TextView\ILAsm-Mode.xshd" /> <EmbeddedResource Include="TextView\ILAsm-Mode.xshd" />
<EmbeddedResource Include="TextView\Asm-Mode.xshd" /> <EmbeddedResource Include="TextView\Asm-Mode.xshd" />
<EmbeddedResource Include="TextView\XML-Mode.xshd" /> <EmbeddedResource Include="TextView\XML-Mode.xshd" />
<None Remove="Properties\launchSettings.json" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

6
ILSpy/Properties/launchSettings.json

@ -2,12 +2,12 @@
"profiles": { "profiles": {
"ILSpy": { "ILSpy": {
"commandName": "Executable", "commandName": "Executable",
"executablePath": ".\\ILSpy.exe", "executablePath": "./ilspy.exe",
"commandLineArgs": "/separate" "commandLineArgs": "--newinstance"
}, },
"ILSpy single-instance": { "ILSpy single-instance": {
"commandName": "Executable", "commandName": "Executable",
"executablePath": ".\\ILSpy.exe" "executablePath": "./ilspy.exe"
} }
} }
} }

6
ILSpy/SingleInstanceHandling.cs

@ -64,10 +64,14 @@ namespace ICSharpCode.ILSpy
{ {
// Fully qualify the paths before passing them to another process, // Fully qualify the paths before passing them to another process,
// because that process might use a different current directory. // because that process might use a different current directory.
if (string.IsNullOrEmpty(argument) || argument[0] == '/') if (string.IsNullOrEmpty(argument) || argument[0] == '-')
return argument; return argument;
try try
{ {
if (argument.StartsWith("@"))
{
return "@" + FullyQualifyPath(argument.Substring(1));
}
return Path.Combine(Environment.CurrentDirectory, argument); return Path.Combine(Environment.CurrentDirectory, argument);
} }
catch (ArgumentException) catch (ArgumentException)

71
doc/Command Line.txt

@ -1,54 +1,27 @@
ILSpy Command Line Arguments ILSpy Command Line Arguments
Command line arguments can be either options or file names. Usage: <Assemblies> [options]
If an argument is a file name, the file will be opened as assembly and added to the current assembly list. @ResponseFile.rsp
Available options: Arguments:
/singleInstance If ILSpy is already running, activates the existing instance Assemblies Assemblies to load
and passes command line arguments to that instance.
This is the default value if /list is not used.
/separate Start up a separate ILSpy instance even if it is already running. Options:
--newinstance Start a new instance of ILSpy even if the user configuration is set to single-instance
/noActivate Do not activate the existing ILSpy instance. This option has no effect -n|--navigateto <TYPENAME> Navigates to the member specified by the given ID string.
if a new ILSpy instance is being started.
/list:listname Specifies the name of the assembly list that is loaded initially.
When this option is not specified, ILSpy loads the previously opened list.
Specify "/list" (without value) to open the default list.
When this option is used, ILSpy will activate an existing instance
only if it uses the same list as specified.
[Note: Assembly Lists are not yet implemented]
/clearList Clears the assembly list before loading the specified assemblies.
[Note: Assembly Lists are not yet implemented]
/navigateTo:tag Navigates to the member specified by the given ID string.
The member is searched for only in the assemblies specified on the command line. The member is searched for only in the assemblies specified on the command line.
Example: 'ILSpy ILSpy.exe /navigateTo:T:ICSharpCode.ILSpy.CommandLineArguments' Example: 'ILSpy ILSpy.exe --navigateTo:T:ICSharpCode.ILSpy.CommandLineArguments'
-s|--search <SEARCHTERM> Search for t:TypeName, m:Member or c:Constant; use exact match (=term),
The syntax of ID strings is described in appendix A of the C# language specification. 'should not contain' (-term) or 'must contain' (+term); use
/reg(ular)?Ex(pressions)?/ or both - t:/Type(Name)?/...
/language:name Selects the specified language. -l|--language <LANGUAGEIDENTIFIER> Selects the specified language.
Example: 'ILSpy /language:C#' or 'ILSpy /language:IL' Example: 'ILSpy --language:C#' or 'ILSpy --language:IL'
-c|--config <CONFIGFILENAME> Provide a specific configuration file.
WM_COPYDATA (SendMessage API): Example: 'ILSpy --config:myconfig.xml'
ILSpy can be controlled by other programs that send a WM_COPYDATA message to its main window. --noactivate Do not activate the existing ILSpy instance.
The message data must be an Unicode (UTF-16) string starting with "ILSpy:\r\n". This option has no effect if a new ILSpy instance is being started.
All lines except the first ("ILSpy:") in that string are handled as command-line arguments.
There must be exactly one argument per line. Note on @ResponseFile.rsp:
That is, by sending this message: * The response file should contain the arguments, one argument per line (not space-separated!).
ILSpy: * Use it when the list of assemblies is too long to fit on the command line.
C:\Assembly.dll
/navigateTo:T:Type
The target ILSpy instance will open C:\Assembly.dll and navigate to the specified type.
ILSpy will return TRUE (1) if it handles the message, and FALSE (0) otherwise.
The /separate option will be ignored; WM_COPYDATA will never start up a new instance.
The /noActivate option has no effect, sending WM_COPYDATA will never activate the window.
Instead, the calling process should use SetForegroundWindow().
If you use /list with WM_COPYDATA, you need to specify /singleInstance as well, otherwise
ILSpy will not handle the message if it has opened a different assembly list.

13
publishlocaldev.ps1

@ -0,0 +1,13 @@
# For local development of the VSIX package - build and publish (VS2022 also needs arm64)
$output_x64 = "./ILSpy/bin/Debug/net8.0-windows/win-x64/publish/fwdependent"
dotnet publish ./ILSpy/ILSpy.csproj -c Debug --no-restore --no-self-contained -r win-x64 -o $output_x64
dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Debug --no-restore --no-self-contained -r win-x64 -o $output_x64
dotnet publish ./ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj -c Debug --no-restore --no-self-contained -r win-x64 -o $output_x64
$output_arm64 = "./ILSpy/bin/Debug/net8.0-windows/win-arm64/publish/fwdependent"
dotnet publish ./ILSpy/ILSpy.csproj -c Debug --no-restore --no-self-contained -r win-arm64 -o $output_arm64
dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Debug --no-restore --no-self-contained -r win-arm64 -o $output_arm64
dotnet publish ./ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj -c Debug --no-restore --no-self-contained -r win-arm64 -o $output_arm64
Loading…
Cancel
Save