Расширение Visual Studio Для Визуализации Экземпляров Пользовательских Классов В Режиме Отладки. Часть 2

Эта статья является продолжением статьи еще в 2014 году.

Напомню, о чем мы говорили в предыдущей статье .



Какую проблему мы решим?

Пишем программное обеспечение на языке С++ , в окружающей среде Визуальная Студия 2015 .

Естественно, в нашем проекте есть пользовательские типы данных.

В качестве примера таких типов могу привести класс МбТвердый .

Этот класс является частью математическое ядро C3D и представляет собой абстракцию твердого тела.

Тело описывается ребрами, грани какими-то поверхностями и т. д. Т.

е.

Структура класса довольно сложная, и в процессе отладки собственных алгоритмов хотелось бы визуально оценить, какое тело представляет собой результат на данный момент. Картинка из предыдущей статьи.

В качестве примера пользовательского класса здесь используется класс сегмента линии.



Расширение Visual Studio для визуализации экземпляров пользовательских классов в режиме отладки.
</p><p>
 Часть 2

Для решения этой проблемы было написано расширение для VisualStudio. Здесь нет ничего интересного, ссылки есть в предыдущей статье.

Но возникла проблема — как расширение VisualStudio может получить данные из адресного пространства (другого) отлаживаемого процесса? Для простых типов данных, таких как массивы, все не так уж и сложно, и Microsoft даже подготовила пример для этого.

станд::вектор .

И в нашем случае МбТвердый В нем есть впечатляющая иерархия наследования и большое количество полей данных.



Изменение пользовательских типов

В предыдущей статье было предложено инвазивное решение этой проблемы.

Поле маркера добавляется в каждый пользовательский класс (который мы хотим визуализировать во время отладки).

И в каждом неконстантном методе класса добавляется код для сериализации данных класса в Общая память .

Поле маркера хранит адрес в Общая память , где мы сохранили данные класса.

В момент отладки при просмотре содержимого интересующей нас переменной расширение VisualStudio находит поле маркера и десериализует данные из Общая память , а потом как-то визуализирует полученные данные.

По понятным причинам такое решение на практике неприменимо.

Особенно, если у нас нет доступа к исходному коду классов, которые мы хотим отладить таким способом.

Ничего лучшего в то время придумать не удалось, и эта тема заглохла на несколько лет.

Сервер в пользовательском процессе

И вот недавно пришла идея написать простой сервер, который будет жить в пользовательском процессе в отдельном потоке и отвечать на запросы, поступающие от нашего расширения VisualStudio. Для сервера за основу был взят проект Microsoft C++ REST SDK .

Этот проект позволил мне быстро написать собственный http-сервер, который принимает GET-запросы и возвращает описание экземпляра пользовательского класса в формате json. Напомню, что нас интересует визуальное представление экземпляров классов.

МбТвердый (твердые).

Запрос к серверу передает адрес переменной в адресном пространстве отлаживаемого процесса.

Т.

к.

сервер живет в одном процессе, он легко может получить доступ к данным по запрошенному адресу.

Сервер, получив адрес экземпляра класса, приводит этот указатель к типу МбТвердый* .

Далее сервер создает аппроксимацию этого тела в виде полигональной сетки.

Сериализует вычисленные вершины и индексы треугольников в json и отправляет ответ. На стороне VisualStudio расширение получает ответ, десериализует данные и рисует полученную полигональную сетку в окне VisualStudio. В результате расширению в VisualStudio даже не нужно знать структуру пользовательских данных, ему достаточно уметь отправлять правильные GET-запросы, десериализовать ответ и рисовать треугольники в окне VisualStudio. Сервер можно расширить.

Таким способом можно отлаживать любые пользовательские классы, которые могут быть представлены в виде полигональной сетки или набора отрезков линий, а расширение VisualStudio может их визуализировать:

Расширение Visual Studio для визуализации экземпляров пользовательских классов в режиме отладки.
</p><p>
 Часть 2

Более того, таким образом мы даже можем отправлять запросы на наш сервер из браузера и визуализировать данные процесса с помощью WebGL. Я сделал простой демонстрационный пример.

Давайте запустим наше приложение.

Открываем страницу примера в браузере, вводим адрес переменной на странице, отправляем запрос на сервер и рисуем ответ. Не знаю, зачем это может быть нужно, но штука классная

Расширение Visual Studio для визуализации экземпляров пользовательских классов в режиме отладки.
</p><p>
 Часть 2



Расширение Visual Studio для визуализации экземпляров пользовательских классов в режиме отладки.
</p><p>
 Часть 2



Возрождение сервера

Все было бы хорошо.

Но есть одна проблема.

При достижении точки останова студия останавливает все потоки пользовательского процесса.

В результате наш сервер также останавливается и не может отвечать на запросы.

Чтобы обойти эту проблему, воспользуемся следующим костылем: текущий поток, в котором сработала точка останова, замораживается, и запускается пользовательский процесс.

В этот момент наш сервер оживает и расширение отправляет ему запрос с адресом интересующей нас переменной.

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

Пользователю кажется, что ничего не произошло и выполнение программы остановилось в точке останова.

В коде расширения VisualStudio этот костыль выглядит так.

Была достигнута точка останова.

Пользователь запрашивает данные для интересующей переменной.

На этом этапе мы останавливаем текущий поток и запускаем отладчик:

  
   

if (dte.Debugger.CurrentMode != EnvDTE.dbgDebugMode.dbgBreakMode) return; currentThread = dte.Debugger.CurrentThread; currentThread.Freeze(); dte.Debugger.Go(false);

Отправляем запрос на сервер.

Мы получаем ответ. Останавливаем процесс и размораживаем наш поток:

if (dte.Debugger.CurrentMode == EnvDTE.dbgDebugMode.dbgBreakMode) return; dte.Debugger.Break(); if (currentThread != null) { currentThread.Thaw(); dte.Debugger.CurrentThread = currentThread; }

Все! Мы получили данные с сервера и отрисовали их в окне VisualStudio. Выполнение программы происходит на исходной точке останова.

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

Теги: #C++ #отладка #Visual Studio #расширения #microsoft #c3d #c3dkernel #c3dtoolkit #C++ #Visual Studio #отладка #Windows Development

Вместе с данным постом часто просматривают: