我有两个项目,一个是“前端”或加载项目,另一个是Web服务,实际上是一个单独的文件夹/解决方案。
我已经在使用我的前端来加载那个项目到Cassini(实际上有两个)。我想做的是将调试器附加到我的两个Web服务及其相关的源代码,在运行时,前端,甚至那些项目,都不包含在前端解决方案中。
我可以访问源代码和pdb,所以我相信我应该能够做到这一点,但不是百分之百确定,并且在网上这样做的信息是......稀疏,充其量。
有没有办法在.NET,Visual Studio SDK或其他第三方框架中执行此操作?
我可以访问VS 2010和VS 2012
答案 0 :(得分:0)
要调用的VS API为EnvDTE.Process.Attach。
API的文档提供了一个按名称附加进程的示例,该示例不适用于多个应用程序池。您可以通过command line tools (may require elevation)或w3wp command line按应用程序池名称找到正确的w3wp流程。
答案 1 :(得分:0)
所以你在这里有几个选择。
第一个选项(如果适用)是添加以下行:
#if DEBUG
System.Diagnostics.Debugger.Launch();
#endif
这通常会弹出“Visual Studio JIT调试”窗口,允许您选择正在运行的实例或启动新的Visual Studio。
或者,如果你想要一些......“更棘手”,你可以迭代运行进程,查找任何Visual Studio实例,并使用EnvDTE
API绑定它们。这是 FAR 更复杂,所以如果适用,我推荐上面更简单的选项,但是这里有:
首先,我们需要一种“查找”Visual Studio实例的方法:
private static IEnumerable<Process> GetVisualStudioProcesses()
{
var processes = Process.GetProcesses();
return processes.Where(o => o.ProcessName.Contains("devenv"));
}
然后我们可以使用它来尝试连接到运行实例的正确的基于COM的接口:
private static bool TryGetVsInstance(int processId, out EnvDTE._DTE instance)
{
var numFetched = IntPtr.Zero;
var monikers = new IMoniker[1];
IRunningObjectTable runningObjectTable;
IEnumMoniker monikerEnumerator;
GetRunningObjectTable(0, out runningObjectTable);
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
{
IBindCtx ctx;
CreateBindCtx(0, out ctx);
string runningObjectName;
monikers[0].GetDisplayName(ctx, null, out runningObjectName);
object runningObjectVal;
runningObjectTable.GetObject(monikers[0], out runningObjectVal);
if (runningObjectVal is EnvDTE._DTE && runningObjectName.StartsWith("!VisualStudio"))
{
var currentProcessId = int.Parse(runningObjectName.Split(':')[1]);
if (currentProcessId == processId)
{
instance = (EnvDTE._DTE)runningObjectVal;
return true;
}
}
}
instance = null;
return false;
}
COM定义是:
[ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
[PreserveSig]
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
public class MessageFilter : IOleMessageFilter
{
private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2;
int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
{
return Handled;
}
int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
return dwRejectType == RetryAllowed ? Retry : Cancel;
}
int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
return WaitAndDispatch;
}
public static void Register()
{
CoRegisterMessageFilter(new MessageFilter());
}
public static void Revoke()
{
CoRegisterMessageFilter(null);
}
private static void CoRegisterMessageFilter(IOleMessageFilter newFilter)
{
IOleMessageFilter oldFilter;
CoRegisterMessageFilter(newFilter, out oldFilter);
}
[DllImport("Ole32.dll")]
private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
}
我们可以将其包含在“尝试附加到”调用中,如下所示:
public static bool AttachToProcess(int processId)
{
#if !DEBUG
// Not allowed if not in DEBUG mode...
return false;
#else
MessageFilter.Register();
Exception lastException = null;
bool attachSuccess = false;
while (!attachSuccess && !(lastException is COMException))
{
Log("Attempting DynamicAttach to process id:" + processId);
try
{
Log("Querying for active VS instances...");
var studioProcesses = GetVisualStudioProcesses();
var studioDtes = studioProcesses
.Select(proc =>
{
EnvDTE._DTE dte;
if (TryGetVsInstance(proc.Id, out dte))
{
return new DteWrapper(dte);
}
return null;
})
.Where(dte => dte != null);
foreach (var studioDte in studioDtes)
{
attachSuccess = TryAttachTo(processId, studioDte, out lastException);
if(attachSuccess) break;
}
}
catch (Exception vsex)
{
lastException = vsex;
}
}
MessageFilter.Revoke();
return attachSuccess;
#endif
}
private static bool TryAttachTo(int processId, DteWrapper studioDte, out Exception lastException)
{
bool attachSuccess = false;
lastException = null;
Log("Attempting to attach to process " + processId);
try
{
var localProcesses =
from localProcess in studioDte.Debugger.LocalProcesses.Cast<EnvDTE.Process>()
let processWrapper = new ProcessWrapper(localProcess)
where processWrapper.Process2 == null || !processWrapper.Process2.IsBeingDebugged
select processWrapper;
if (!localProcesses.Any())
{
lastException = new ApplicationException("Can not find process to attach to!");
return false;
}
foreach (var process in localProcesses)
{
try
{
if (process.Process.ProcessID == processId)
{
Log("Found dte process to attach to, attempting attach...", studioDte);
try
{
process.Process.Attach();
Log("Attached to process!");
attachSuccess = true;
AtLeastOneDebuggerWasAttached = true;
}
catch (Exception detachException)
{
Log("Could not attach to process:" + detachException, studioDte);
attachSuccess = false;
lastException = detachException;
}
}
}
catch (Exception attachException)
{
lastException = attachException;
}
}
}
catch (Exception queryProcessesException)
{
lastException = queryProcessesException;
}
return attachSuccess;
}
将一些辅助类定义为:
internal class DteWrapper
{
public DteWrapper(EnvDTE._DTE dte)
{
Dte = dte as EnvDTE.DTE;
Dte2 = dte as EnvDTE80.DTE2;
Debugger = dte.Debugger;
Debugger2 = (Dte2 != null) ? Dte2.Debugger as EnvDTE80.Debugger2 : null;
Events = dte.Events;
DebuggerEvents = dte.Events.DebuggerEvents;
}
public EnvDTE.DTE Dte { get; private set; }
public EnvDTE80.DTE2 Dte2 { get; private set; }
public EnvDTE.Debugger Debugger { get; private set; }
public EnvDTE80.Debugger2 Debugger2 { get; private set; }
public EnvDTE.Events Events { get; private set; }
public EnvDTE.DebuggerEvents DebuggerEvents { get; private set; }
}
internal class ProcessWrapper
{
public ProcessWrapper(EnvDTE.Process dteProcess)
{
this.Process = dteProcess;
this.Process2 = dteProcess as EnvDTE80.Process2;
this.Process3 = dteProcess as EnvDTE90.Process3;
this.ManagedProcess = System.Diagnostics.Process.GetProcessById(dteProcess.ProcessID);
}
public Process ManagedProcess { get; private set; }
public EnvDTE.Process Process { get; private set; }
public EnvDTE80.Process2 Process2 { get; private set; }
public EnvDTE90.Process3 Process3 { get; private set; }
}