Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в эту темуОткрыть новую тему
> VisualStudio Profile, Автоматический режим отладки
StaticZ
сообщение 3.7.2014, 19:37
Сообщение #1


*********

Разработчик проекта "Квинтэссенция"
Сообщений: 2.155
Регистрация: 15.6.2009
Группа: Пользователи
Наличность: 0
Из: РФ, Москва
Пользователь №: 11.948



У RunUO есть хорошая штука под названием CrashGuard, которая позволяет ей перезапускать саму себя в случае возникновения исключения. Это действительно полезно для реального сервера, но вызывает неудобства при отладке и тестирования, т.к. после подобного перезапуска сервер не подключается к отладчику, что вынуждает вручную его перезапускать. На все это уходит время... Конечно наиболее простым решением было бы просто отключение CrashGuard в DEBUG конфигурации, но так как мы легких путей не ищем, то задача свелась к тому чтобы заставить RunUO аттачить саму себя к отладчику MVS. Возможно это может показаться безумным и сложным, но на самом деле все достаточно просто, ведь MVS предлагает нам средства для взаимодействия с IDE. Собственно нам потребуется сама MVS версии 2010/2012 или позднее (в принципе возможно использовать и более старые версии, но тогда надо изменить используемые версии интерфейсов, в принципе их также лучше обновить если доступны более новые). После чего добавляем в референсы ядра следующие сборки: envdte, EnvDTE100, envdte80, envdte90, EnvDTE90a. Ну и добавляем сей код в пространство имен Server.Diagnostics:


Код

/***************************************************************************
*            QServer (UO: Quintessense)         Created by :        StaticZ
*                                               url : http://dev.uoquint.ru
*    file: VisualStudio.cs (2012.08.16)         email :  staticz@uoquint.ru
***************************************************************************/

using System.IO;
using EnvDTE;
using EnvDTE80;
using EnvDTE90;
using EnvDTE90a;
using EnvDTE100;
using DTEVStudio = EnvDTE80.DTE2;
using DTEProcess = EnvDTE90a.Process4;
using DTEDebuger = EnvDTE100.Debugger5;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Process = System.Diagnostics.Process;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace Server.Diagnostics
{
    public class VisualStudio
    {
        #region DllImport

        [DllImport("User32")]
        private static extern int ShowWindow(int hwnd, int nCmdShow);

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

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

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetFocus(IntPtr hWnd);

        #endregion

        protected static string GetSolutionForVisualStudio(Process visualStudioProcess)
        {
            DTEVStudio visualStudioInstance;
            if (TryGetVsInstance(visualStudioProcess.Id, out visualStudioInstance)) {
                try {
                    return visualStudioInstance.Solution.FullName;
                } catch (Exception) { }
            }
            return null;
        }

        protected static Process GetAttachedVisualStudio(Process applicationProcess)
        {
            IEnumerable<Process> visualStudios = GetVisualStudioProcesses();

            foreach (Process visualStudio in visualStudios) {
                DTEVStudio visualStudioInstance;
                if (TryGetVsInstance(visualStudio.Id, out visualStudioInstance)) {
                    try {
                        foreach (Process debuggedProcess in visualStudioInstance.Debugger.DebuggedProcesses) {
                            if (debuggedProcess.Id == applicationProcess.Id) {
                                return debuggedProcess;
                            }
                        }
                    } catch (Exception) { }
                }
            }
            return null;
        }

        protected static void AttachVisualStudioToProcess(Process visualStudioProcess, Process applicationProcess)
        {
            if (TryGetVsInstance(visualStudioProcess.Id, out visualStudioInstance))
            {          
                while (true) try {
                    var localProcesses = ((DTEDebuger)visualStudioInstance.Debugger).LocalProcesses;
                    processToAttachTo = (DTEProcess)localProcesses.Cast<EnvDTE.Process>().FirstOrDefault(process => process.ProcessID == applicationProcess.Id);  
                    break;
                } catch { System.Threading.Thread.Sleep(100); }

                if (processToAttachTo != null) {
                    if (processToAttachTo.IsBeingDebugged || GetAttachedVisualStudio(applicationProcess) != null)
                        return;

                    processToAttachTo.Attach();
                
                    ShowWindow((int)visualStudioProcess.MainWindowHandle, 3);
                    SetForegroundWindow(visualStudioProcess.MainWindowHandle);
                } else {
                    throw new InvalidOperationException("Visual Studio process cannot find specified application '" + applicationProcess.Id + "'");
                }
            }
        }

        protected static Process GetVisualStudioForSolutions(List<string> solutionNames)
        {
            foreach (string solution in solutionNames) {
                Process visualStudioForSolution = GetVisualStudioForSolution(solution);
                if (visualStudioForSolution != null) {
                    return visualStudioForSolution;
                }
            }
            return null;
        }

        protected static Process GetVisualStudioForSolution(string solutionName)
        {
            IEnumerable<Process> visualStudios = GetVisualStudioProcesses();

            foreach (Process visualStudio in visualStudios) {
                DTEVStudio visualStudioInstance;
                if (TryGetVsInstance(visualStudio.Id, out visualStudioInstance)) {
                    try {
                        string actualSolutionName = Path.GetFileName(visualStudioInstance.Solution.FullName);
                        if (string.Compare(actualSolutionName, solutionName, StringComparison.InvariantCultureIgnoreCase) == 0) {
                            return visualStudio;
                        }
                    } catch (Exception) { }
                }
            }
            return null;
        }

        private static IEnumerable<Process> GetVisualStudioProcesses()
        {
            Process[] processes = Process.GetProcesses();
            return processes.Where(o => o.ProcessName.Contains("devenv"));
        }

        private static bool TryGetVsInstance(int processId, out DTEVStudio instance)
        {
            IntPtr numFetched = IntPtr.Zero;
            IRunningObjectTable runningObjectTable;
            IEnumMoniker monikerEnumerator;
            IMoniker[] monikers = new IMoniker[1];

            GetRunningObjectTable(0, out runningObjectTable);
            runningObjectTable.EnumRunning(out monikerEnumerator);
            monikerEnumerator.Reset();

            while (monikerEnumerator.Next(1, monikers, numFetched) == 0) {
                IBindCtx ctx;
                CreateBindCtx(0, out ctx);

                string runningObjectName;
                monikers[0].GetDisplayName(ctx, null, out runningObjectName);

                object runningObjectVal;
                runningObjectTable.GetObject(monikers[0], out runningObjectVal);

                if (runningObjectVal is DTEVStudio && runningObjectName.StartsWith("!VisualStudio")) {
                    int currentProcessId = int.Parse(runningObjectName.Split(':')[1]);

                    if (currentProcessId == processId) {
                        instance = (DTEVStudio)runningObjectVal;
                        return true;
                    }
                }
            }

            instance = null;
            return false;
        }
      
        private static DTEVStudio visualStudioInstance;
        private static DTEProcess processToAttachTo;

        public static bool Attached {
            get { return (visualStudioInstance != null && processToAttachTo != null); }
        }

        [Conditional("DEBUG")]
        public static void Attach(string solution)
        {
            AttachVisualStudioToProcess(GetVisualStudioForSolution(solution), Process.GetCurrentProcess());
            
            Timer.DelayCall(TimeSpan.FromSeconds(1D), TimeSpan.FromSeconds(1D), new TimerCallback(CheckAttaching_Callback));
        }

        private static void CheckAttaching_Callback()
        {
            try {
                if (!processToAttachTo.IsBeingDebugged) {
                    visualStudioInstance = null;
                    Core.Kill(false);
                }
            } catch {;}
        }

        //private static void OnStopDebugging(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        //{
        //    OnStopDebugging(Guid, ID, CustomIn, CustomOut);
        //}

        //private static void OnStopDebugging(string Guid, int ID, object CustomIn, object CustomOut)
        //{
        //    visualStudioInstance = null;
        //    Core.Kill(false);
        //}

        [Conditional("DEBUG")]
        public static void Dettach()
        {
            try {
                if (processToAttachTo != null && visualStudioInstance != null)
                    processToAttachTo.Detach(false);
            } catch {
                Console.WriteLine("Error ocuires while dettaching debug process");
            } finally {
                visualStudioInstance = null;
                processToAttachTo = null;
            }
        }

        [Conditional("DEBUG")]
        public static void Breakpoint(bool conditional = true)
        {
            if (!conditional || !Attached) return;
            var currentFram = new StackTrace(true).GetFrame(1);          
            visualStudioInstance.Debugger.Break(false);
        }
    }

}



Все что нам теперь надо это лишь вызвать метод Attach при запуске сервера и передать ему в качестве параметра имя файла решения вашего сервера:
Код
public static void Main(string[] args)
{
    VisualStudio.Attach("UOQuintessence.sln");
    // ... Original code behind
}



Итак, теперь при запуске в DEBUG конфигурации RunUO будет автоматически присоединяться к отладчику студии, в которой открыто решение с указанным названием файла. Это легко проверить запустив проект без отладки, вы увидите что не смотря на это он все равно перейдет в режим отладки, тоже самое будет и при рестарте сервера.

В качестве небольшого бонуса еще небольшая мелочь это метод - Breakpoint(bool conditional = true), что ставит брейкпоинт в случае выполнения условия. Зачем оно нужно? Часто требуется во время отладки посмотреть что-то конкретное, к примеру мы хотим проверить проверку при хотьбе и ставим брекпоинт и начинаем сходить с ума, т.к. он вызывается каждым мобайлом, но использовав:
Код
VisualStudio.Breakpoint(from.Type = typeof(PlayerMobile));

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


Оригинальный текст статьи находиться тут: board.uoquint.ru

Сообщение отредактировал StaticZ - 3.7.2014, 20:29


--------------------
RP сервер UO: Quintessence, а также ПО: EssenceUCS, EssenceUDK, CentrEd+, Fiddler+ и др.
Game isn't a dream, it is the reality, reality which is coming while we dream...
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия | Версия для КПК Сейчас: 28.3.2024, 15:47
Designed by Nickostyle