Visual Studio 2010 DTE: как сделать добавленную ссылку на DLL абсолютной, а не скопированной - PullRequest
8 голосов
/ 13 июля 2011

Сводка:

Нам нужно продублировать поведение диалогового окна Добавить ссылку, используя DTE, когда вы добавляете конкретную DLL (она добавляет запись пути подсказки к ссылке в файле CSProj).

** Примечание: есть еще один связанный, но не дублированный, пост от меня здесь: https://stackoverflow.com/questions/6690655/visual-studio-2010-add-in-how-to-get-a-references-hint-path-property Пожалуйста, прочитайте его также для получения дополнительной информации об этой проблеме.Теперь я добавил достойную награду, чтобы получить ответ на этот вопрос, и с радостью распределю голоса за любые приличные ответы:) *

История на данный момент:

Я конвертирую ссылку на проектк прямой ссылке на DLL программно с использованием DTE.

Если у меня есть простое решение с Project2 (проект parent ), которое ссылается на Project1 (проект child ), я внесу изменениенапример:

project1Reference = FindProjectReference(project2.References, project1);
project1Reference.Remove();
Reference dllReference = project2.References.Add(project1DllPath);

, где project1DllPath ссылается на файл "c:\somewhere\Project1\Bin\Debug\Project1.dll".

Проблема, которую я пока не могу решить, состоит в том, что новая ссылка не - "c:\somewhere\Project1\Bin\Debug\Project1.dll" но вместо этого указывает на "c:\somewhere\Project2\Bin\Debug\Project1.dll" (и файл копируется туда).

Если я добавляю DLL напрямую / вручную с помощью меню Добавить ссылку, это не делает это копирование.

Как добавить ссылку на DLL в библиотеку DLL существующего проекта без ее копирования и ссылки на нее вместо этого?

Я пытался добавить dllReference.CopyLocal = false; после добавления, но помимо установки флагаэто не имело никакого значения.Кажется, что нет никаких вариантов изменить путь после создания.

Обновление: я также попытался программно удалить любую зависимость Build от Project1 из Project2, но это не имело никакого эффекта.Разница между файлами csproj:

Как проект:

  <ItemGroup>
    <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
      <Project>{86B3E118-2CD1-49E7-A180-C1346EC223B9}</Project>
      <Name>ClassLibrary1</Name>
    </ProjectReference>
  </ItemGroup>

В качестве ссылки на DLL (путь был полностью потерян):

 <ItemGroup>
    <Reference Include="ClassLibrary1, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    ...
  </ItemGroup>

В качестве DLL-библиотеки, на которую ссылаются вручную:

  <ItemGroup>
    <Reference Include="ClassLibrary1, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
      <HintPath>..\ClassLibrary1\bin\Debug\ClassLibrary1.dll</HintPath>
    </Reference>
    ...
  </ItemGroup>

Похоже, возможность указать путь подсказки для ссылки на DLL - это ключ. Как задать путь подсказки для ссылки DLL (при условии, что у вас есть только дескриптор свойства Reference)?

Дополнительная информация (20 июля 2011 г.):

Предложение из Muse VSExtensions ниже не влияет на рассматриваемые библиотеки DLL, так как уже была сделана копия из проекта BIN библиотеки DLL в папку BIN родительского проекта.Родительский проект не использует ссылочный путь, поскольку в его выходной папке уже есть дочерняя DLL.

Также Reference Paths проекта сохраняются в проекте Файл .csproj.user, а не файл проекта .csproj.

Ответы [ 5 ]

10 голосов
/ 27 июля 2011

Я убежден, что это новая ошибка / функция в VS 2010, потому что у меня есть надстройка, которая начала показывать подобное поведение пару дней назад после того, как я перенесла ее из VS 2008 ... В основном, если вы добавитессылка на что-либо в пути поиска сборки VS, она будет добавлена ​​без подсказки пути.

Мне удалось найти другие надстройки VS, которые решили эту проблему (Power Tools, NuGet и другие), и все оникажется, использовать MsBuild.Я не знаю, сильно ли MsBuild увеличивает использование ресурсов - я сам не видел слишком большого замедления, возможно, потому что References.Add () очень медленный для начала.Но обратите внимание, что для получения экземпляра проекта MsBuild используется метод «GetLoadedProjects», который может означать, что он работает с данными, уже присутствующими в памяти.

Ниже приведен код, который я использовал для исправления своего дополнения.в, это упрощенная версия того, что я нашел в сети ... По сути, идея состоит в том, чтобы добавить ссылку как обычно, а затем использовать MsBuild, чтобы установить подсказку пути.Установка подсказки является тривиальной операцией, но поиск экземпляра элемента проекта MsBuild для добавления подсказки невероятно сложен.Я пытался взломать альтернативу, используя только MsBuild, но столкнулся с другими проблемами ... Кажется, это работает.

Еще одна вещь, которая может быть здесь интересна: код содержит своего рода оптимизацию - он не добавляет подсказку к новой ссылке, если путь ссылки равен пути, который мы хотели добавить.Это достаточно для рассматриваемого случая и правильно определяет, когда VS решает использовать dll из выходной папки вместо того, что мы сказали.Но когда я попытался добавить ссылку на dll, уже находящуюся в выходной папке (я использую одну выходную папку для многих связанных проектов), надстройка не установила путь подсказки, и проект, похоже, переключился на использование какой-либо другой dllв пути (в моем случае это из его папки PublicAssemblies) ... Так что может быть полезно удалить эту строку "if (! newRef.Path.Equals (...") и добавить подсказку всегда. Явсе еще расследует этот случай, поэтому любые дополнительные - хм, подсказки или улучшения кода приветствуются.

string newFileName = "the path to your.dll";
VSLangProj.VSProject containingProject = yourProject;

VSLangProj.Reference newRef;

newRef = containingProject.References.Add(newFileName);
if (!newRef.Path.Equals(newFileName, StringComparison.OrdinalIgnoreCase))
{
    Microsoft.Build.Evaluation.Project msBuildProj = Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.GetLoadedProjects(containingProject.Project.FullName).First();
    Microsoft.Build.Evaluation.ProjectItem msBuildRef = null;

    AssemblyName newFileAssemblyName = AssemblyName.GetAssemblyName(newFileName);
    foreach(var item in msBuildProj.GetItems("Reference"))
    {
        AssemblyName refAssemblyName = null;
        try 
        {
            refAssemblyName = new AssemblyName(item.EvaluatedInclude);
        }
        catch {}

        if (refAssemblyName != null)
        {
            var refToken = refAssemblyName.GetPublicKeyToken();
            var newToken = newFileAssemblyName.GetPublicKeyToken();

            if
            (
                refAssemblyName.Name.Equals(newFileAssemblyName.Name, StringComparison.OrdinalIgnoreCase)
                && ((refAssemblyName.Version != null && refAssemblyName.Version.Equals(newFileAssemblyName.Version))
                    || (refAssemblyName.Version == null && newFileAssemblyName.Version == null))
                && (refAssemblyName.CultureInfo != null && (refAssemblyName.CultureInfo.Equals(newFileAssemblyName.CultureInfo))
                    || (refAssemblyName.CultureInfo == null && newFileAssemblyName.CultureInfo == null))
                && ((refToken != null && newToken != null && Enumerable.SequenceEqual(refToken, newToken))
                    || (refToken == null && newToken == null))
            )
            {
                msBuildRef = item;
                break;
            }
        }
    }

    if (msBuildRef != null)
    {
        Uri newFileUri = new Uri(newFileName);
        Uri projectUri = new Uri(Path.GetDirectoryName(containingProject.Project.FullName).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar);

        Uri relativeUri = projectUri.MakeRelativeUri(newFileUri);
        msBuildRef.SetMetadataValue("HintPath", relativeUri.ToString());
    }
}
2 голосов
/ 26 июля 2011

Нужно ли решать эту проблему, используя только DTE? Для этого можно использовать автоматизацию MSBuild ... у нее есть классы, которые могут анализировать содержимое файла csproj.

Взгляните на: Microsoft.Build.Evaluation Namespace , есть некоторая полезная информация о том, как загрузить файл csproj и как его изменить. См. Также Класс проекта .

0 голосов
/ 07 августа 2012

Недавно у меня возникла проблема с добавлением ссылки dll в Visual Studio 2010, я не мог заставить ее добавить HintPath, что вызвало проблему со сборкой TFS.Я заметил, что надстройка Productivity Power Tools, которую я установил несколько недель назад, изменила диалоговое окно добавления ссылок.Я отключил «Диалоговое окно« Добавить ссылку для поиска »надстройки из меню« Инструменты », и после перезапуска Visual Studio 2010 я снова был счастлив - я смог добавить ссылку, и на этот раз там был и HintPath.

0 голосов
/ 23 июля 2011

Трудно отклонить хороший вызов ... Я не там, но я думаю, что у меня есть некоторые приличные подсказки, чтобы продвинуться вперед.
Прежде всего, я создаю небольшой тестовый плагин, чтобы воспроизвести вашу проблему, и ... Я потерпел неудачу!

    foreach (Project project in (object[])_applicationObject.ActiveSolutionProjects)
    {
        ((VSProject)project.Object).References.Add(@"c:\temp\test\FromFolder\bin\debug\KmlLib.dll");
    }

Это случайная dll где-то на моем диске.DLL не подписана и попала в мой csproj как (именно то, что вы хотите сделать):

   <Reference Include="KmlLib">
      <HintPath>..\..\FromFolder\bin\debug\KmlLib.dll</HintPath>
    </Reference>

Тогда я заметил, что ваша dll была подписана.Это тоже не имело никакого значения.Следующий тест, который я сделал, был скопировать некоторые стандартные MS DLL.Я выбрал VsWebSite.Interop.dll из \ Program Files \ Microsoft Visual Studio 10.0 \ Common7 \ IDE \ PublicAssemblies \ и скопировал его в папку FromFolder \ bin \ debug \, добавив, что в качестве ссылки неожиданно воспроизвел ваш сценарий> Я получил включение, но неhintpath.
Затем последний тест: я переименовал VsWebSite.Interop.dll в xxVsWebSite.Interop.dll и включил эту dll.Внезапно hintpath был добавлен снова!

Объединяя все это и ваше описание вместе, я предполагаю, что при добавлении ссылочной VS сначала проверяется, найдена ли указанная dll в ее текущих местоположениях поиска (GAC, папка Project, путь(?), ..) Если это так, то подсказка не добавляется.Если он не может быть найден, тогда требуется указание hintpath.

Чтобы проверить, справится ли эта теория, вы можете выполнить два теста:

  • Скопировать ссылочную dll всовершенно другая папка, а затем ссылка оттуда -> по-прежнему не будет содержать подсказку, потому что dll с той же сигнатурой все еще находится в 'path'
  • Скопируйте и переименуйте ссылочную dll в совершенно другую папку и укажите ссылку нановое имя -> следует добавить подсказку

Интересно узнать о ваших результатах:)

0 голосов
/ 20 июля 2011

Для решения этой проблемы вам нужно добавить ссылочный путь в Свойства проекта из DTE

Чтобы установить ссылочный путь в Visual Studio:

  1. В обозревателе решений выберите проект.
  2. В меню Проект выберите Свойства.
  3. Щелкните по ссылочным путям.
  4. В текстовом поле Папка укажите путь к папке, содержащей сборки. Чтобы перейти к папке, нажмите многоточие (…).
  5. Нажмите Добавить папку.

Вы должны сделать то же самое с объекта автоматизации

Дайте мне знать, если это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...