调试Visual Studio宏中引用的自定义dll

Ton*_*Nam 9 c# debugging dll step-into visual-studio-macros

我之前问过: 添加对visual studio宏的dll引用

用我的语言(C#)创建宏的想法使得创建宏更容易.问题是我无法调试dll

为了解决我试过的问题:

  1. myClassLibrary.pdb接下来myClassLibrary.dll希望我可以通过步入它们来调试dll中的方法.

  2. 创建了WCF服务.因为我不知道如何从vba引用服务,所以我从类库中引用它.问题是我需要使用变量,例如DTE.ActiveDocument,这些变量不可序列化,这意味着我无法将它们传递给wcf服务.

在C#中工作的想法非常好但是无法调试并且看到发生了什么使得它有点困难.我可能不得不转到我的旧选项,我在C#上创建了我的代码然后用反射器反编译成vba.


编辑

我想我已经接近了解决方案.我想为什么不在控制台应用程序中创建宏?我能够获取活动文档文本但无法更改它.

        EnvDTE80.DTE2 MyDte;
        MyDte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject( "VisualStudio.DTE.10.0" );
        Console.WriteLine( "The Edition is " + MyDte.Edition );

        Console.ReadLine( );

        // write to the console the text that is selected. "sometimes it does not work don't know why"
        Console.WriteLine(
            MyDte.ActiveDocument.Selection.Text
        );
Run Code Online (Sandbox Code Playgroud)

注意我添加了以下引用加上vba宏具有的onces:

在此输入图像描述

Ton*_*Nam 5

最后这是解决方案:

在下面的步骤中,我将描述如何调试将由宏执行的dll.

如果你想做一些像这样的事情:

在此输入图像描述 (注意我在视觉工作室上调用c#上的宏!)

  1. 在visual studio中创建一个新的解决方案 在此输入图像描述

  2. 现在为该解决方案添加一个新的类库Project.(这是将执行宏的类)在此输入图像描述

  3. 添加参考文献EnvDTE,EbvDTE100,EnvDTE80,EnvDTE90,EnvDTE90a.基本上与visual studio宏具有相同的参考:在此输入图像描述

  4. 创建一个方法,该方法将执行您计划在类库上使用的宏.

       namespace ClassLibrary1
       {
           public static class Class1
           {
               public static void Macro1(EnvDTE80.DTE2 DTE)
               {
                   // make sure an active text document is open before calling this method
                   DTE.ActiveDocument.Selection.Insert("Hello World!!!");
               }
           }
       }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 添加另一个项目(Visual Studio加载项)在此输入图像描述

  6. 跟随wizzard离开默认值,除了第4页选择: 在此输入图像描述

  7. 继续选择向导上的默认选项,直到创建项目: 在此输入图像描述

  8. 将该项目设置为启动项目,以便当我们按f5时,addin运行.

  9. 将MyAddin1中的引用添加到类库中

  10. 一旦我们有了这个引用,我们应该能够从addin执行宏.为了这样做打开Connect.cs并导航到方法Exec添加ClassLibrary1.Class1.Macro1(_applicationObject);所以它看起来像: 在此输入图像描述

  11. 在Exec方法的开头添加一个断点,以便我们可以调试它.

  12. 按下执行MyAddin1 F5.应该打开视觉工作室的新实例.

  13. 在visual studio的新实例上打开任何解决方案.在这种情况下,我再次打开相同的解决方案>

  14. 获得工具然后单击MyAddin1但确保文档已打开: 在此输入图像描述

  15. 一旦你点击我的插件,你应该到达断点! 在此输入图像描述

15.注意!出于某种原因,我不得不评论这条线ClassLibrary1.Class1.Macro1(_applicationObject);

所以我评论出那条线并在我放置的那条线上:

 var textDoc = (TextDocument)(_applicationObject.ActiveDocument.Object(string.Empty));
 textDoc.Selection.Insert("Hello world");
Run Code Online (Sandbox Code Playgroud)

最后,当我点击位于工具上的MyAddin1时,会插入Hello world!


一旦我知道宏运行正常,我可以将类导出到类库,并让宏调用dll上的方法而不是插件.


Ton*_*Nam 2

我还有另一个更好的答案!

我创建该插件的唯一原因是我需要 DTE 的引用。为什么不引用我需要的 dte。

算法如下:

  1. 使用 classIde获取 Visual Studio 任何实例的 DTE。

  2. 一旦你有了这个 dte,就可以创建宏。

这是 Ide 类:

public class Ide
{        
    [DllImport("ole32.dll")]
    private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);

    [DllImport("ole32.dll")]
    private static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

    public static DTE2 GetDte(string solutionName)
    {
        DTE2 dte = null;

        GetDte((displayName, x) =>
        {
            if (System.IO.Path.GetFileName(x.Solution.FullName).Contains(solutionName))
            {
                dte = x;
                return false; // we found it stop seraching
            }
            else
            {
                return true; // continue searching
            }

        });

        return dte;
    }

    public static DTE2 GetDte(int processId)
    {
        DTE2 dte = null;

        GetDte((displayName, x) =>
        {
            if (displayName.Contains(processId.ToString()))
            {
                dte = x;
                return false; // stop searching we found matching dte
            }
            else
            {
                return true; // continue searching
            }
        });

        return dte;
    }

    public static List<DTE2> GetAllDte()
    {
        List<DTE2> list = new List<DTE2>();
        GetDte((displayName, x) =>
        {
            list.Add(x);
            return true; // continue serching we want all dte's
        });
        return list;
    }

    private static void GetDte(Func<string, DTE2, bool> foo)
    {
        Dictionary<string, string> dtesProcessIds = new Dictionary<string, string>();

        //rot entry for visual studio running under current process.            
        IRunningObjectTable rot;
        GetRunningObjectTable(0, out rot);
        IEnumMoniker enumMoniker;
        rot.EnumRunning(out enumMoniker);
        enumMoniker.Reset();
        IntPtr fetched = IntPtr.Zero;
        IMoniker[] moniker = new IMoniker[1];
        while (enumMoniker.Next(1, moniker, fetched) == 0)
        {
            IBindCtx bindCtx;
            CreateBindCtx(0, out bindCtx);
            string displayName;
            moniker[0].GetDisplayName(bindCtx, null, out displayName);
            object comObject;
            rot.GetObject(moniker[0], out comObject);

            if (comObject != null)
            {
                DTE2 dteCurrent = null;
                try
                {
                    dteCurrent = (EnvDTE80.DTE2)comObject;

                    // if solution is not open continue
                    // this will cause an exception if it is not open
                    var temp = dteCurrent.Solution.IsOpen;

                    string solName = dteCurrent.Solution.FullName;

                    // if there is an instance of visual studio with no solution open continue                        
                    if (string.IsNullOrEmpty(solName))
                    {
                        continue;
                    }

                    // avoid adding duplicate ide's
                    if (dtesProcessIds.ContainsKey(displayName) == false)
                    {
                        dtesProcessIds.Add(displayName, displayName);
                    }
                    else
                    {
                        continue;
                    }

                }
                catch (System.Runtime.InteropServices.COMException e)
                {
                    continue;
                }
                catch (Exception e)
                {
                    continue;
                }
                if (dteCurrent != null)
                {
                    var cont = foo(displayName, dteCurrent);

                    if (cont == false)
                        return;
                }
            }

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

那么如果我有一个正在运行的 Visual Studio 实例,其中包含具有该名称的解决方案,ConsoleApp1那么我将能够执行以下操作:

 var dte = Ide.GetDte("ConsoleApp1");
 dte.ActiveDocument.Selection.Insert("My macro is working!");
Run Code Online (Sandbox Code Playgroud)

并且文本My macro is working!将被插入到活动文档中。确保有一个活动文档