Проект расширяемости SSMS — как исследовать/отладить

В духе этого ответа относительно создания расширения SSMS:

namespace SSMSAddin
{
    using System;
    using System.IO;
    using Extensibility;
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.VisualStudio.CommandBars;
    using Microsoft.SqlServer.Management.UI.VSIntegration;
    using System.Windows.Forms;

    public class Connect : IDTExtensibility2, IDTCommandTarget
    {
        private DTE2 applicationObject;
        private CommandEvents executeSqlEvents;
        private AddIn addInInstance;

        public Connect() { }

        public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            this.applicationObject = (DTE2)application;
            this.addInInstance = (AddIn)addInInst;

            this.applicationObject = (DTE2)application;
            this.executeSqlEvents = this.applicationObject.Events.CommandEvents["{52692960-56BC-4989-B5D3-94C47A513E8D}", 1];
            this.executeSqlEvents.BeforeExecute += this.ExecuteSqlEventsBeforeExecute;

            if (connectMode == ext_ConnectMode.ext_cm_UISetup)
            {
                var contextGUIDS = new object[] { };
                var commands = (Commands2)this.applicationObject.Commands;
                string toolsMenuName = "Tools";

                //Place the command on the tools menu.
                //Find the MenuBar command bar, which is the top-level command bar holding all the main menu items:
                CommandBar menuBarCommandBar = ((CommandBars)this.applicationObject.CommandBars)["MenuBar"];

                //Find the Tools command bar on the MenuBar command bar:
                CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
                CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

                //This try/catch block can be duplicated if you wish to add multiple commands to be handled by your Add-in,
                //  just make sure you also update the QueryStatus/Exec method to include the new command names.
                try
                {
                    //Add a command to the Commands collection:
                    Command command = commands.AddNamedCommand2(this.addInInstance, "SSMSAddin", "SSMSAddin", "Executes the command for SSMSAddin", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

                    //Add a control for the command to the tools menu:
                    if ((command != null) && (toolsPopup != null))
                    {
                        command.AddControl(toolsPopup.CommandBar, 1);
                    }
                }
                catch (ArgumentException)
                {
                    //If we are here, then the exception is probably because a command with that name
                    //  already exists. If so there is no need to recreate the command and we can 
                    //  safely ignore the exception.
                }
            }
        }

        private void ExecuteSqlEventsBeforeExecute(string guid, int id, object customin, object customout, ref bool canceldefault)
        {
            try
            {
                Document document = ((DTE2)ServiceCache.ExtensibilityModel).ActiveDocument;
                var textDocument = (TextDocument)document.Object("TextDocument");

                string queryText = textDocument.Selection.Text;

                if (string.IsNullOrEmpty(queryText))
                {
                    EditPoint startPoint = textDocument.StartPoint.CreateEditPoint();
                    queryText = startPoint.GetText(textDocument.EndPoint);
                }

                DateTime now = DateTime.Now;
                // string server = 
                string folderPath = string.Format(@"B:\SSMS Queries\{0}", now.ToString("yyyyMMdd"));
                string fileName = now.ToString("yyyyMMdd-HHmmss") + ".sql";
                Directory.CreateDirectory(folderPath);
                string fullPath = Path.Combine(folderPath, fileName);
                File.WriteAllText(fullPath, queryText);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) { }

        public void OnAddInsUpdate(ref Array custom) { }

        public void OnStartupComplete(ref Array custom) { }

        public void OnBeginShutdown(ref Array custom) { }

        public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
        {
            if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
            {
                if (commandName == "SSMSAddin.Connect.SSMSAddin")
                {
                    status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
                    return;
                }
            }
        }

        public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
        {
            handled = false;
            if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
            {
                if (commandName == "SSMSAddin.Connect.SSMSAddin")
                {
                    var document = ((DTE2)ServiceCache.ExtensibilityModel).ActiveDocument;
                    if (document != null)
                    {
                        //replace currently selected text
                        var selection = (TextSelection)document.Selection;
                        selection.Insert(
@"Welcome to SSMS. This sample is brought to you by

SSMSBoost add-in team

Check www.ssmsboost.com for updates.",
(Int32)EnvDTE.vsInsertFlags.vsInsertFlagsContainNewText);
                    }

                    handled = true;
                    return;
                }
            }
        }
    }
}

Код добавляет событие, которое срабатывает перед каждым выполнением SQL в SSMS 2012... Я нажимаю F5, выполняется SQL-запрос, но перед его выполнением копия запроса сохраняется в B:\SSMS Queries\20130225\083000.sql.

Чего в этом не хватает? Я хочу добавить параметры для используемого соединения/базы данных, скажем, например, B:\SSMS Queries\Localhost\Northwind\20130225\083000.sql (Просто пример).

То, что я обычно делаю... Точка останова, пошаговое выполнение, проверка объектов и т.д.... Однако это аддон. Классная библиотека. Вы не можете поставить точку останова/пройти через библиотеку...

Как установить точку останова в библиотеке классов, которая загружается в SSMS/Visual Studio, чтобы я мог проводить исследования? Или что было бы хорошим ресурсом для такого рода мастерства? Где-то в object customin, object customout находится информация, с которой я хочу поработать.


person WernerCD    schedule 26.02.2013    source источник
comment
На вкладке отладки свойств проекта настройте его для запуска внешней программы и введите путь к SSMS 2012 (например, C:\Program Files (x86)\Microsoft SQL Server\110\Tools\Binn\ManagementStudio\Ssms.exe), затем вы можете поставить точку останова и запустить его в режиме отладки. Также см. информацию здесь о файле SSMSAddin.addin.   -  person Martin Smith    schedule 26.02.2013
comment
@MartinSmith Если я компилирую, перемещаю файлы SSMSAddin DDL и Addin в папку и запускаю SSMS 2012, все работает - запросы сохраняются в папку. Если я укажу VS2012 на SSMS2012, а затем F10, он выдаст ошибку PInvokeStackImbalance. Так что я могу использовать надстройку, но не могу ее отлаживать. Хотел бы я поставить вам +10, кстати :)   -  person WernerCD    schedule 26.02.2013
comment
Странно... это дает мне несколько ошибок, но если я продолжаю нажимать F5, я в конечном итоге попадаю в точку останова.   -  person WernerCD    schedule 26.02.2013
comment
Вы можете отключить проверку PInvoke. Подробности здесь (см. шаг 15)   -  person Martin Smith    schedule 26.02.2013
comment
Как вы получаете имя сервера и имя БД? локальный хост, северный ветер? Я знаю, что анализ ActiveWindow.Caption - плохой вариант...   -  person WernerCD    schedule 26.02.2013
comment
Не знаю. Если я когда-либо узнал, когда писал ответ на связанный вопрос, я сейчас забыл!   -  person Martin Smith    schedule 27.02.2013


Ответы (2)


Вторая часть вопроса, чтобы найти подключение к текущей базе данных..

Добавьте ссылку на Microsoft.SqlServer.RegSrvrEnum.dll и SqlWorkBench.Interfaces (расположенные где-то в вашем C:\ProgramFiles..\SQL Server.. -). Убедитесь, что вы установили SDK для инструментов.

Тогда приведенный ниже код должен помочь (добро пожаловать!)

IScriptFactory scriptFactory = ServiceCache.ScriptFactory;
CurrentlyActiveWndConnectionInfo connectionIfno = scriptFactory.CurrentlyActiveWndConnectionInfo;
UIConnectionInfo conn = connectionIfno.UIConnectionInfo;
Debug.WriteLine("{0}::{1}", conn.ServerName, conn.AdvancedOptions["DATABASE"]);
person Console.WriteLine    schedule 06.08.2014

На самом деле документирую свой ответ (после того, как несколько раз забыл). Нашел свой ответ в сочетании SSMSBoost и TSQLTidy.Blogspot (и комментарий Мартина Смита)

1) Set SSMS as the startup project inside Debug Profile. File location for SSMS2012:
    C:\Program Files (x86)\Microsoft SQL Server\110\Tools\Binn\ManagementStudio\SSMS.exe
2) I've created 2 Addin files:
    MyAddin.Debug.Addin
    MyAddin.Release.Addin
    (Contents updated as listed below)
3) Add postbuild event to create directory if not exists
4) Add postbuild event to copy Addin from ProjectDir to MSeventShared
5) Turn off P-Invoke warnings. Press CRLT + ALT + E - In Managed Debugging Assistants, find PInvokeStackImbalance, untick it.

Файлы надстроек (выпуск изменяет расположение DLL из каталога проекта в папку MSEnvShared\Admin):

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility">
    <HostApplication>
        <Name>Microsoft SQL Server Management Studio</Name>
        <Version>*</Version>
    </HostApplication>
    <Addin>
        <FriendlyName>MyAddin.</FriendlyName>
        <Description>MyAddin Description.</Description>
        <Assembly>C:\Projects\MyAddin\bin\Debug\MyAddin.dll</Assembly>
        <FullClassName>SSMSAddin.Connect</FullClassName>
        <LoadBehavior>0</LoadBehavior>
    <CommandPreload>1</CommandPreload>
    <CommandLineSafe>0</CommandLineSafe>
     </Addin>
</Extensibility>

Событие после сборки:

cmd /x /c mkdir "C:\ProgramData\Microsoft\MSEnvShared\Addins\"
cmd /C copy "$(ProjectDir)MyAddin.$(ConfigurationName).Addin" "C:\C:\ProgramData\Microsoft\MSEnvShared\Addins\MyAddin.Addin"
person WernerCD    schedule 31.10.2013