forked from CosmosOS/Cosmos
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Work on debugger and fix assembly name in templates.
- Loading branch information
1 parent
0fef242
commit aaee21a
Showing
19 changed files
with
514 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
namespace Cosmos.VS.DebugEngine | ||
{ | ||
public static class CmdIDList | ||
{ | ||
public const int DebugLaunchCmdID = 0x0100; | ||
public const int DebugExecCmdID = 0x0101; | ||
public const int DebugLogCmdID = 0x0102; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using System; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.VisualStudio; | ||
using Microsoft.VisualStudio.OLE.Interop; | ||
using Microsoft.VisualStudio.Shell; | ||
using IServiceProvider = System.IServiceProvider; | ||
|
||
namespace Cosmos.VS.DebugEngine.Commands | ||
{ | ||
public abstract class BaseDebugCommand | ||
{ | ||
protected IServiceProvider serviceProvider; | ||
|
||
protected BaseDebugCommand(IServiceProvider serviceProvider) | ||
{ | ||
this.serviceProvider = serviceProvider; | ||
} | ||
|
||
public virtual int Execute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
protected static int EnsureString(IntPtr pvaIn, out string arguments) | ||
{ | ||
arguments = null; | ||
if (pvaIn == IntPtr.Zero) | ||
{ | ||
// No arguments. | ||
return VSConstants.E_INVALIDARG; | ||
} | ||
|
||
object vaInObject = Marshal.GetObjectForNativeVariant(pvaIn); | ||
if (vaInObject == null || vaInObject.GetType() != typeof(string)) | ||
{ | ||
return VSConstants.E_INVALIDARG; | ||
} | ||
|
||
arguments = vaInObject as string; | ||
return VSConstants.S_OK; | ||
} | ||
|
||
protected static bool IsQueryParameterList(System.IntPtr pvaIn, System.IntPtr pvaOut, uint nCmdexecopt) | ||
{ | ||
ushort lo = (ushort)(nCmdexecopt & (uint)0xffff); | ||
ushort hi = (ushort)(nCmdexecopt >> 16); | ||
if (lo == (ushort)OLECMDEXECOPT.OLECMDEXECOPT_SHOWHELP) | ||
{ | ||
if (hi == VsMenus.VSCmdOptQueryParameterList) | ||
{ | ||
if (pvaOut != IntPtr.Zero) | ||
{ | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
source/Cosmos.VS.DebugEngine/Commands/DebugCommandHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System; | ||
using Microsoft.VisualStudio; | ||
using Microsoft.VisualStudio.OLE.Interop; | ||
using IServiceProvider = System.IServiceProvider; | ||
|
||
namespace Cosmos.VS.DebugEngine.Commands | ||
{ | ||
public delegate int DebugCommandExecute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut); | ||
|
||
public class DebugCommandHandler | ||
{ | ||
public DebugCommandHandler(IServiceProvider serviceProvider) | ||
{ | ||
var launchCommand = new DebugLaunchCommand(serviceProvider); | ||
OnDebugLaunch += launchCommand.Execute; | ||
|
||
var logCommand = new DebugLogCommand(serviceProvider); | ||
OnDebugLog += logCommand.Execute; | ||
|
||
var execCommand = new DebugExecCommand(serviceProvider); | ||
OnDebugExec += execCommand.Execute; | ||
} | ||
|
||
public event DebugCommandExecute OnDebugLaunch; | ||
public event DebugCommandExecute OnDebugExec; | ||
public event DebugCommandExecute OnDebugLog; | ||
|
||
public int Execute(uint nCmdID, uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut) | ||
{ | ||
switch (nCmdID) | ||
{ | ||
case CmdIDList.DebugLaunchCmdID: | ||
if (OnDebugLaunch != null) | ||
{ | ||
return OnDebugLaunch(nCmdExecOpt, pvaIn, pvaOut); | ||
} | ||
break; | ||
case CmdIDList.DebugExecCmdID: | ||
if (OnDebugExec != null) | ||
{ | ||
return OnDebugExec(nCmdExecOpt, pvaIn, pvaOut); | ||
} | ||
break; | ||
case CmdIDList.DebugLogCmdID: | ||
if (OnDebugLog != null) | ||
{ | ||
return OnDebugLog(nCmdExecOpt, pvaIn, pvaOut); | ||
} | ||
break; | ||
} | ||
global::System.Diagnostics.Debug.Fail("Unknown command id"); | ||
return VSConstants.E_NOTIMPL; | ||
} | ||
|
||
public int Query(uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) | ||
{ | ||
switch (prgCmds[0].cmdID) | ||
{ | ||
case CmdIDList.DebugLaunchCmdID: | ||
case CmdIDList.DebugExecCmdID: | ||
case CmdIDList.DebugLogCmdID: | ||
prgCmds[0].cmdf |= (uint)(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_INVISIBLE); | ||
return VSConstants.S_OK; | ||
} | ||
|
||
global::System.Diagnostics.Debug.Fail("Unknown command id"); | ||
return VSConstants.E_NOTIMPL; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
using System; | ||
using System.Globalization; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.VisualStudio; | ||
using Microsoft.VisualStudio.Shell.Interop; | ||
|
||
namespace Cosmos.VS.DebugEngine.Commands | ||
{ | ||
public class DebugExecCommand : BaseDebugCommand | ||
{ | ||
public DebugExecCommand(IServiceProvider serviceProvider) | ||
: base(serviceProvider) | ||
{ | ||
} | ||
|
||
public override int Execute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut) | ||
{ | ||
int hr; | ||
|
||
if (IsQueryParameterList(pvaIn, pvaOut, nCmdExecOpt)) | ||
{ | ||
Marshal.GetNativeVariantForObject("$", pvaOut); | ||
return VSConstants.S_OK; | ||
} | ||
|
||
string arguments; | ||
hr = EnsureString(pvaIn, out arguments); | ||
if (hr != VSConstants.S_OK) | ||
return hr; | ||
|
||
if (string.IsNullOrWhiteSpace(arguments)) | ||
throw new ArgumentException("Expected an MI command to execute (ex: Debug.MIDebugExec info sharedlibrary)"); | ||
|
||
DebugExec(arguments); | ||
|
||
return VSConstants.S_OK; | ||
} | ||
|
||
private void DebugExec(string command) | ||
{ | ||
var commandWindow = (IVsCommandWindow)serviceProvider.GetService(typeof(SVsCommandWindow)); | ||
bool atBreak = false; | ||
var debugger = serviceProvider.GetService(typeof(SVsShellDebugger)) as IVsDebugger; | ||
if (debugger != null) | ||
{ | ||
DBGMODE[] mode = new DBGMODE[1]; | ||
if (debugger.GetMode(mode) == VSConstants.S_OK) | ||
{ | ||
atBreak = mode[0] == DBGMODE.DBGMODE_Break; | ||
} | ||
} | ||
|
||
string results = null; | ||
|
||
try | ||
{ | ||
if (atBreak) | ||
{ | ||
commandWindow.ExecuteCommand(String.Format(CultureInfo.InvariantCulture, "Debug.EvaluateStatement -exec {0}", command)); | ||
} | ||
else | ||
{ | ||
//results = await MIDebugCommandDispatcher.ExecuteCommand(command); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
if (e.InnerException != null) | ||
{ | ||
e = e.InnerException; | ||
} | ||
|
||
commandWindow.Print($"Error: {e.Message}\r\n"); | ||
} | ||
|
||
if (results != null && results.Length > 0) | ||
{ | ||
// Make sure that we are printing whole lines | ||
if (!results.EndsWith("\n") && !results.EndsWith("\r\n")) | ||
{ | ||
results = results + "\n"; | ||
} | ||
|
||
commandWindow.Print(results); | ||
} | ||
} | ||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
source/Cosmos.VS.DebugEngine/Commands/DebugLaunchCommand.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
using System; | ||
using System.Globalization; | ||
using System.IO; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.VisualStudio; | ||
using Microsoft.VisualStudio.Shell.Interop; | ||
|
||
namespace Cosmos.VS.DebugEngine.Commands | ||
{ | ||
public class DebugLaunchCommand : BaseDebugCommand | ||
{ | ||
private const string DebugLaunchCommandSyntax = "E,Executable:!(d) O,OptionsFile:!(d)"; | ||
|
||
private enum DebugLaunchCommandSwitchEnum | ||
{ | ||
Executable, | ||
OptionsFile | ||
} | ||
|
||
public DebugLaunchCommand(IServiceProvider serviceProvider) | ||
: base(serviceProvider) | ||
{ | ||
} | ||
|
||
public override int Execute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut) | ||
{ | ||
int hr; | ||
|
||
if (IsQueryParameterList(pvaIn, pvaOut, nCmdExecOpt)) | ||
{ | ||
Marshal.GetNativeVariantForObject("$ /switchdefs:\"" + DebugLaunchCommandSyntax + "\"", pvaOut); | ||
return VSConstants.S_OK; | ||
} | ||
|
||
string arguments; | ||
hr = EnsureString(pvaIn, out arguments); | ||
if (hr != VSConstants.S_OK) | ||
return hr; | ||
|
||
IVsParseCommandLine parseCommandLine = (IVsParseCommandLine)serviceProvider.GetService(typeof(SVsParseCommandLine)); | ||
hr = parseCommandLine.ParseCommandTail(arguments, iMaxParams: -1); | ||
if (ErrorHandler.Failed(hr)) | ||
return hr; | ||
|
||
hr = parseCommandLine.HasParams(); | ||
if (ErrorHandler.Failed(hr)) | ||
return hr; | ||
if (hr == VSConstants.S_OK || parseCommandLine.HasSwitches() != VSConstants.S_OK) | ||
{ | ||
string message = string.Concat("Unexpected syntax for MIDebugLaunch command. Expected:\n", | ||
"Debug.MIDebugLaunch /Executable:<path_or_logical_name> /OptionsFile:<path>"); | ||
throw new ApplicationException(message); | ||
} | ||
|
||
hr = parseCommandLine.EvaluateSwitches(DebugLaunchCommandSyntax); | ||
if (ErrorHandler.Failed(hr)) | ||
return hr; | ||
|
||
string executable; | ||
if (parseCommandLine.GetSwitchValue((int)DebugLaunchCommandSwitchEnum.Executable, out executable) != VSConstants.S_OK || | ||
string.IsNullOrWhiteSpace(executable)) | ||
{ | ||
throw new ArgumentException("Executable must be specified"); | ||
} | ||
|
||
bool checkExecutableExists = false; | ||
string options = string.Empty; | ||
|
||
string optionsFilePath; | ||
if (parseCommandLine.GetSwitchValue((int)DebugLaunchCommandSwitchEnum.OptionsFile, out optionsFilePath) == 0) | ||
{ | ||
// When using the options file, we want to allow the executable to be just a logical name, but if | ||
// one enters a real path, we should make sure it isn't mistyped. If the path contains a slash, we assume it | ||
// is meant to be a real path so enforce that it exists | ||
checkExecutableExists = (executable.IndexOf('\\') >= 0); | ||
|
||
if (string.IsNullOrWhiteSpace(optionsFilePath)) | ||
throw new ArgumentException("Value expected for '/OptionsFile' option"); | ||
|
||
if (!File.Exists(optionsFilePath)) | ||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Options file '{0}' does not exist", optionsFilePath)); | ||
|
||
options = File.ReadAllText(optionsFilePath); | ||
} | ||
|
||
if (checkExecutableExists) | ||
{ | ||
if (!File.Exists(executable)) | ||
{ | ||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Executable '{0}' does not exist", executable)); | ||
} | ||
|
||
executable = Path.GetFullPath(executable); | ||
} | ||
|
||
LaunchDebugTarget(executable, options); | ||
|
||
return 0; | ||
} | ||
|
||
private void LaunchDebugTarget(string filePath, string options) | ||
{ | ||
IVsDebugger4 debugger = (IVsDebugger4)serviceProvider.GetService(typeof(IVsDebugger)); | ||
VsDebugTargetInfo4[] debugTargets = new VsDebugTargetInfo4[1]; | ||
debugTargets[0].dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess; | ||
debugTargets[0].bstrExe = filePath; | ||
debugTargets[0].bstrOptions = options; | ||
debugTargets[0].guidLaunchDebugEngine = Guids.DebugEngineGuid; | ||
VsDebugTargetProcessInfo[] processInfo = new VsDebugTargetProcessInfo[debugTargets.Length]; | ||
|
||
debugger.LaunchDebugTargets4(1, debugTargets, processInfo); | ||
} | ||
|
||
} | ||
} |
Oops, something went wrong.