调试Silverlight中的WPF应用程序
我正在开发包含加载Silverlight应用程序WebBrowser控件一个WPF应用程序。我希望能够从Visual Studio(F5)启动应用程序,并将调试器附加到silverlight代码。不过,我没有任何运气。调试Silverlight中的WPF应用程序
我目前能做的最好是启动应用程序不附加,那么一旦它运行起来,使用Silverlight作为调试的指定类型的代码手动附加到这个过程中,这一点也适用。 (当我导致Web浏览器控件加载Silverlight应用程序时,它会在我的Silverlight代码中达到断点)。我已经编写了一些宏来实现这个启动/附加的自动化,但它仍然不是最好的。
我已经试过指定WPF应用程序作为外部程序启动/调试Silverlight应用程序时运行,但Visual Studio的重视想要调试托管.NET代码的过程。
任何想法?理想情况下,我真的想附加到进程并调试托管的.NET和Silverlight代码,但我认为这是不可能的。我真的很想在启动时自动附加到Silverlight代码,这样我就可以轻松地调试Silverlight应用程序的所有问题,包括加载时发生的问题。
感谢您的想法Brandorf和脂肪。 Brandorf几乎把我带到了我想去的地方,但确实需要我的SL应用程序能够独立运行。我真的希望只有一个应用程序,它是wpf和silverlight,SL端正在调试。
很长一段时间后,我问这个问题(我忘了我曾问在这里),我居然拼凑起来,我很快乐的事情的解决方案。我在我的应用程序的WPF/.NET一侧使用Visual Studio自动化来查找Visual Studio的所有正在运行的实例,找出哪一个产生了我的exe(因为它通常位于vcproj/sln文件夹下面的文件夹中),然后使用Visual Studio自动化将VS附加到应用程序,调试silverlight代码。完成后,我再加载我的silverlight内容。
它工作得很好。你最终会得到一个应用程序,它会在每次运行时发现一个调试器附加到它自己(所以你可能只需要在调试版本中或者某种程度上可以关闭该代码)。所以,只要你想调试silverlight端,你就可以通过Visual Studio的ctrl-F5启动应用程序(无需调试即可启动)。
这里是我的代码:
#if DEBUG
using System;
using System.Collections.Generic;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO;
namespace Launcher
{
//The core methods in this class to find all running instances of VS are
//taken/inspired from
//http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx
class DebuggingAutomation
{
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved,
out UCOMIRunningObjectTable prot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(int reserved,
out UCOMIBindCtx ppbc);
///<summary>
///Get a snapshot of the running object table (ROT).
///</summary>
///<returns>
///A hashtable mapping the name of the object
///in the ROT to the corresponding object
///</returns>
private static Hashtable GetRunningObjectTable()
{
Hashtable result = new Hashtable();
int numFetched;
UCOMIRunningObjectTable runningObjectTable;
UCOMIEnumMoniker monikerEnumerator;
UCOMIMoniker[] monikers = new UCOMIMoniker[1];
GetRunningObjectTable(0, out runningObjectTable);
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
while (monikerEnumerator.Next(1, monikers, out numFetched) == 0)
{
UCOMIBindCtx ctx;
CreateBindCtx(0, out ctx);
string runningObjectName;
monikers[0].GetDisplayName(ctx, null, out runningObjectName);
object runningObjectVal;
runningObjectTable.GetObject(monikers[0], out runningObjectVal);
result[runningObjectName] = runningObjectVal;
}
return result;
}
/// <summary>
/// Get a table of the currently running instances of the Visual Studio .NET IDE.
/// </summary>
/// <param name="openSolutionsOnly">
/// Only return instances that have opened a solution
/// </param>
/// <returns>
/// A list of the ides (as DTE objects) present in
/// in the running object table to the corresponding DTE object
/// </returns>
private static List<EnvDTE.DTE> GetIDEInstances(bool openSolutionsOnly)
{
var runningIDEInstances = new List<EnvDTE.DTE>();
Hashtable runningObjects = GetRunningObjectTable();
IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator();
while (rotEnumerator.MoveNext())
{
string candidateName = (string)rotEnumerator.Key;
if (!candidateName.StartsWith("!VisualStudio.DTE"))
continue;
EnvDTE.DTE ide = rotEnumerator.Value as EnvDTE.DTE;
if (ide == null)
continue;
if (openSolutionsOnly)
{
try
{
string solutionFile = ide.Solution.FullName;
if (!String.IsNullOrEmpty(solutionFile))
{
runningIDEInstances.Add(ide);
}
}
catch { }
}
else
{
runningIDEInstances.Add(ide);
}
}
return runningIDEInstances;
}
internal static void AttachDebuggerIfPossible()
{
if (System.Diagnostics.Debugger.IsAttached)
{
//Probably debugging host (Desktop .NET side), so don't try to attach to silverlight side
return;
}
var ides = GetIDEInstances(true);
var fullPathToAssembly = System.Reflection.Assembly.GetExecutingAssembly().Location;
var potentials = new List<EnvDTE.DTE>();
foreach (var ide in ides)
{
var solutionPath = ide.Solution.FullName;
var topLevelSolutionDir = Path.GetDirectoryName(solutionPath);
var assemblyName = fullPathToAssembly;
if (assemblyName.StartsWith(topLevelSolutionDir, StringComparison.OrdinalIgnoreCase))
{
potentials.Add(ide);
}
}
EnvDTE.DTE chosenIde = null;
//If you have multiple ides open that can match your exe, you can come up with a scheme to pick a particular one
//(eg, put a file like solution.sln.pickme next to the solution whose ide you want to debug). If this is not a
//concern, just pick the first match.
if (potentials.Count > 0)
{
chosenIde = potentials[0];
}
var dbg = chosenIde != null ? (EnvDTE80.Debugger2)chosenIde.Debugger : null;
if (dbg != null)
{
var trans = dbg.Transports.Item("Default");
var proc = (EnvDTE80.Process2)dbg.GetProcesses(trans, System.Environment.MachineName).Item(Path.GetFileName(fullPathToAssembly));
var engines = new EnvDTE80.Engine[1];
engines[0] = trans.Engines.Item("Silverlight");
proc.Attach2(engines);
}
}
}
}
#endif
这有点在黑暗中拍摄的,但假设你的Silverlight应用程序能够在它自己的运行,你可以在你的解决方案设置,设置Visual Studio来启动这两个应用程序一起,你应附两个都。
如果您不能添加Silverlight项目到解决方案(将自动启动调试),您可能能够使用这个技巧的。这将同时加载这两个项目
http://saraford.net/2008/07/28/did-you-know-you-can-start-debugging-multiple-projects-268/
您可以举报此作为微软的一个功能或者错误连接,我觉得这只是因为它是假设它为WPF应用程序进行调试,如果它不是任何浏览器。 – 2011-07-14 16:51:24