diff --git a/ILSpy.AddIn/Commands/OpenILSpyCommand.cs b/ILSpy.AddIn/Commands/OpenILSpyCommand.cs index 8e8e48193..6f1261d3c 100644 --- a/ILSpy.AddIn/Commands/OpenILSpyCommand.cs +++ b/ILSpy.AddIn/Commands/OpenILSpyCommand.cs @@ -12,18 +12,6 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy.AddIn.Commands { - public class ILSpyParameters - { - public ILSpyParameters(IEnumerable assemblyFileNames, params string[] arguments) - { - this.AssemblyFileNames = assemblyFileNames; - this.Arguments = arguments; - } - - public IEnumerable AssemblyFileNames { get; private set; } - public string[] Arguments { get; private set; } - } - public class DetectedReference { public DetectedReference(string name, string assemblyFile, bool isProjectReference) @@ -75,12 +63,8 @@ namespace ICSharpCode.ILSpy.AddIn.Commands } } - string commandLineArguments = Utils.ArgumentArrayToCommandLine(parameters.AssemblyFileNames.ToArray()); - if (parameters.Arguments != null) { - commandLineArguments = string.Concat(commandLineArguments, " ", Utils.ArgumentArrayToCommandLine(parameters.Arguments)); - } - - System.Diagnostics.Process.Start(GetILSpyPath(), commandLineArguments); + var ilspyExe = new ILSpyInstance(parameters); + ilspyExe.Start(); } protected Dictionary GetReferences(Microsoft.CodeAnalysis.Project parentProject) @@ -140,7 +124,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands protected override void OnExecute(object sender, EventArgs e) { - System.Diagnostics.Process.Start(GetILSpyPath()); + new ILSpyInstance().Start(); } internal static void Register(ILSpyAddInPackage owner) diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj index ee784cab3..01817bbcf 100644 --- a/ILSpy.AddIn/ILSpy.AddIn.csproj +++ b/ILSpy.AddIn/ILSpy.AddIn.csproj @@ -74,6 +74,7 @@ + True True diff --git a/ILSpy.AddIn/ILSpyInstance.cs b/ILSpy.AddIn/ILSpyInstance.cs new file mode 100644 index 000000000..fe4ee1abc --- /dev/null +++ b/ILSpy.AddIn/ILSpyInstance.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ICSharpCode.ILSpy.AddIn +{ + class ILSpyParameters + { + public ILSpyParameters(IEnumerable assemblyFileNames, params string[] arguments) + { + this.AssemblyFileNames = assemblyFileNames; + this.Arguments = arguments; + } + + public IEnumerable AssemblyFileNames { get; private set; } + public string[] Arguments { get; private set; } + } + + class ILSpyInstance + { + ILSpyParameters parameters; + + public ILSpyInstance() + { + } + + public ILSpyInstance(ILSpyParameters parameters) + { + this.parameters = parameters; + } + + static string GetILSpyPath() + { + var basePath = Path.GetDirectoryName(typeof(ILSpyAddInPackage).Assembly.Location); + return Path.Combine(basePath, "ILSpy.exe"); + } + + public void Start() + { + var commandLineArguments = parameters.AssemblyFileNames?.Concat(parameters.Arguments); + + var process = new Process() { + StartInfo = new ProcessStartInfo() { + FileName = GetILSpyPath(), + UseShellExecute = false + } + }; + process.Start(); + + if ((commandLineArguments != null) && commandLineArguments.Any()) { + // Only need a message to started process if there are any parameters to pass + SendMessage(process, "ILSpy:\r\n" + string.Join(Environment.NewLine, commandLineArguments), true); + } + } + + void SendMessage(Process ilspyProcess, string message, bool activate) + { + // 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) => { + uint processId = NativeMethods.GetProcessIdFromWindow(hWnd); + //if (processId == ilspyProcess.Id) { + Debug.WriteLine("Found {0:x4} for process {1}", hWnd, processId); + string windowTitle = NativeMethods.GetWindowText(hWnd, 100); + if (windowTitle.StartsWith("ILSpy", StringComparison.Ordinal)) { + Debug.WriteLine("Found {0:x4}: {1}", hWnd, windowTitle); + IntPtr result = Send(hWnd, message); + Debug.WriteLine("WM_COPYDATA result: {0:x8}", result); + if (result == (IntPtr)1) { + if (activate) + NativeMethods.SetForegroundWindow(hWnd); + success = true; + return false; // stop enumeration + } + } + //} + return true; // continue enumeration + }, IntPtr.Zero); + + // Wait some time before next attempt + await Task.Delay(500); + remainingAttempts--; + } while (!success && (remainingAttempts > 0)); + }); + } + + unsafe static IntPtr Send(IntPtr hWnd, string message) + { + const uint SMTO_NORMAL = 0; + + CopyDataStruct lParam; + 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; + } + } + } + } +} diff --git a/ILSpy/NativeMethods.cs b/ILSpy/NativeMethods.cs index 1513d66ae..f2eb56989 100644 --- a/ILSpy/NativeMethods.cs +++ b/ILSpy/NativeMethods.cs @@ -50,6 +50,20 @@ namespace ICSharpCode.ILSpy [DllImport("user32.dll", CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetForegroundWindow(IntPtr hWnd); + + //HANDLE WINAPI GetProcessHandleFromHwnd( + // _In_ HWND hwnd + //); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.I4)] + internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, [MarshalAs(UnmanagedType.I4)] out uint processId); + + public static uint GetProcessIdFromWindow(IntPtr hWnd) + { + GetWindowThreadProcessId(hWnd, out uint processId); + return processId; + } } [return: MarshalAs(UnmanagedType.Bool)]