4

I am developing a WPF app that contains a webbrowser control that loads a silverlight application. I would like to be able to launch the app from visual studio (F5) and have the debugger attach to the silverlight code. However, I've not had any luck with this.

The best I can currently do is to launch the app without attaching, then once it is up and running, attach to the process manually with silverlight as the specified type of code to debug, and this works. (When I cause the web browser control to load the silverlight app, it will hit breakpoints in my silverlight code). I've written some macros to automate this launching/attaching somewhat, but it still isn't the best.

I've tried specifying the WPF app as the external program to run when launching/debugging the silverlight app, but Visual Studio attaches to the process wanting to debug the managed .NET code.

Any ideas? Ideally, I would really like to attach to the process and debug both the managed .NET and the silverlight code, but I don't think this is possible. I'd really like to automatically be attached to the silverlight code at launch so that I can easily debug all issues with the silverlight app, including those that occur on load.

aggieNick02
  • 2,557
  • 2
  • 23
  • 36
  • You can report this as a feature or bug at Microsoft connect, I think it is just because it is assuming it as WPF app to debug if it is not any browser. – Akash Kava Jul 14 '11 at 16:51

3 Answers3

1

Thanks for your ideas Brandorf and fatty. Brandorf's almost gets me to where I wanted to go, but does require that my SL app be capable of running on its own. I really want to have only the one app, which is both wpf and silverlight, with the SL side being debugged.

A long time after I asked this question (I forgot I had asked it here), I actually pieced together a solution that I'm really happy with. I use visual studio automation within the WPF/.NET side of my app, to find all running instances of visual studio, figure out which one produced my exe (since it typically sits in a folder below the vcproj/sln folder), and then use visual studio automation to have that VS attach to the app, debugging silverlight code. After this is done, I then load my silverlight content.

It works really well. You end up with an app that goes and finds a debugger to attach to itself every time it runs (so you probably want this code only in a debug build, or somehow able to be turned off). So you just launch the app with ctrl-F5 (launch without debugging) from visual studio whenever you want to debug the silverlight side.

Here's my code:

#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 
aggieNick02
  • 2,557
  • 2
  • 23
  • 36
0

It's a bit of a shot in the dark, but assuming your silverlight app is capable of running on its own, you can, under your solution settings, set visual studio to start both apps together, and you should be attached to both of them.

Brandorf
  • 787
  • 3
  • 16
0

If you can't add the Silverlight project to your solution (which will start debugging automatically), you might be able to make use of this tip. It will load both projects at the same time

http://saraford.net/2008/07/28/did-you-know-you-can-start-debugging-multiple-projects-268/

fatty
  • 2,453
  • 2
  • 25
  • 24