Шаблоны T4 - обновление обозревателя решений в Visual Studio 2010 из одного домена приложения в другой - PullRequest
3 голосов
/ 10 октября 2011
<#@ template debug="true" hostspecific="true" language="C#" #>  
<#@ assembly name="EnvDTE80" #>  
<#@ include file="T4Toolbox.tt" #>  
<#  
IServiceProvider serviceProvider = (IServiceProvider)this.Host;  
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)serviceProvider.GetService(typeof(EnvDTE.DTE));  
//add a file to a project and add its dependupon build property. 
//I want to refresh teh solution explorer window to show the hierarchy between 2 files
//You will see this kind of relationship between Forms.cs and Form1.Designer.cs files.

EnvDTE.UIHierarchy solExplorer = dte.ToolWindows.SolutionExplorer;  
solExplorer.Parent.Activate();  
dte.ExecuteCommand("View.Refresh", string.Empty); 

Я пытаюсь обновить окно инструментов обозревателя решений, чтобы я мог видеть вновь созданные файлы, вложенные.Я знаю, что шаблоны T4 выполняются в одном домене приложения, а вызовы выполняются в домене приложений Visual Studio с использованием удаленного взаимодействия.Я получаю эту ошибку о сериализации.Таким образом, есть способ, которым я могу обновить окно инструмента обозревателя решений (solExplorer.Parent), сначала активировав его (мне сказали).

Введите 'Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase' in Assembly 'Microsoft.VisualStudio.Platform.WindowManagement, версия = 10.0.0.0, культура = нейтральная, PublicKeyToken = b03f5f7f11d50a3a 'не помечена как сериализуемая.

Обновление : на основе комментария Герета.
Спасибо, Герет, я пробовал это, но он возвращает COMException,
У меня нет ошибки о сериализации Microsoft.VisualStudioКласс .Platform.WindowManagement.DTE.WindowBase и метод Activate, похоже, успешно выполнены. Ошибка теперь в методе dte.ExecuteCommand .

//object dteObject = GetCOMService(serviceProvider, typeof(EnvDTE80.DTE2)); 
object dteObject1 = GetCOMService(serviceProvider, typeof(EnvDTE.DTE));
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)dteObject1;

При выполнении этой строки возникло исключение COMException:

dte.ExecuteCommand("View.Refresh", string.Empty);  

Сообщение "Ошибка HRESULT E_FAIL был возвращен извызов компонента COM. "
Источник" EnvDTE80 "
StackTrace" в EnvDTE80.DTE2.ExecuteCommand (String CommandName, String CommandArgs)
ErrorCode -2147467259

Что попробовать дальше?

Спасибо, Рад

Ответы [ 3 ]

2 голосов
/ 15 октября 2011

Есть раздел команд DTE, которые не остаются с маршалингом COM, как только CLR замечает, что оба конца канала удаленного взаимодействия записаны в управляемом коде.Однако, учитывая, что эти компоненты на самом деле не настроены для использования в качестве удаленных .Net, но ARE настроены для использования в качестве удаленных COM, возникает такой тип ошибки.

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

public static Object GetCOMService(IServiceProvider provider, Type type)
{
    Object ret;
    ret = provider.GetService(type);
    if (ret == null)
    {
        return ret;
    }

    try
    {
        return Marshal.GetObjectForIUnknown(Marshal.GetIUnknownForObject(ret));
    }
    catch (Exception)
    {
        return ret;
    }
}
0 голосов
/ 04 июля 2015

Спасибо, Гарет.Ваше решение работает очень хорошо.Я расширил метод GetService:

    private T GetService<T>(Type type) where T : class
    {
        IServiceProvider hostServiceProvider = (IServiceProvider)Host;
        if (hostServiceProvider == null)
        {
            throw new Exception("Host property returned unexpected value (null)");
        }
        object serviceObj = hostServiceProvider.GetService(type);
        try
        {
            serviceObj = Marshal.GetObjectForIUnknown(Marshal.GetIUnknownForObject(serviceObj));
        }
        catch (Exception) { }
        T service = serviceObj as T;
        if (service == null)
        {
            throw new Exception("Unable to retrieve service");
        }
        return service;
    }
0 голосов
/ 21 мая 2013

Я наконец-то заставил это работать, выгрузив и перезагрузив проект. Проект должен быть выбран в обозревателе решений, в противном случае вы получите исключение COMException.

IServiceProvider hostServiceProvider = (IServiceProvider)Host;
// see @GarethJ's answer for the following
DTE2 dte2 = GetCOMService(hostServiceProvider, typeof(EnvDTE.DTE)) as DTE2;
object dteObject1 = GetCOMService(hostServiceProvider, typeof(EnvDTE.DTE));
EnvDTE80.DTE2 dte2 = (EnvDTE80.DTE2)dteObject1;

var solExplorer = dte2.ToolWindows.SolutionExplorer;  
solExplorer.Parent.Activate();
ProjectItem containingProjectItem = dte2.Solution.FindProjectItem(templateFile);
Project project = containingProjectItem.ContainingProject;

UIHierarchy solExplorerHierarchy = solExplorer.Parent.Object as UIHierarchy;
string projectSolutionPath = Path.Combine(dte2.Solution.Properties.Item("Name").Value.ToString(), project.Name);
var projectItem = solExplorerHierarchy.GetItem(projectSolutionPath);
projectItem.Select(vsUISelectionType.vsUISelectionTypeSelect);
dte2.ExecuteCommand("Project.UnloadProject", ""); 
dte2.ExecuteCommand("Project.ReloadProject", "");

И тогда появляются все вновь созданные вложенные элементы. Я использую VS2012 и T4Toolbox 11.7.

...