Visual Studio 2010 DTE: как сделать добавленную ссылку DLL абсолютной и не скопированной

резюме:

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

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

история такова:

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

Предположим, у меня есть простое решение с Project2 (the родитель project), который ссылается на Project1 (the ребенок project), я делаю изменения, как это:

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

где project1DllPath относится к .

проблема, которую я еще не могу решить, заключается в том, что новая ссылка не для "c:somewhereProject1BinDebugProject1.dll" а "c:somewhereProject2BinDebugProject1.dll" (и файл копируется туда).

если я добавляю DLL напрямую / вручную, используя меню Add Reference, он не делает этого копирования.

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

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

Update: я также попытался программно удалить любую зависимость сборки от Project1 из Project2, но это не повлияло.

Ниже приведена разница между файлами csproj:

проект:

  <ItemGroup>
    <ProjectReference Include="..ClassLibrary1ClassLibrary1.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>..ClassLibrary1binDebugClassLibrary1.dll</HintPath>
    </Reference>
    ...
  </ItemGroup>

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

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

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

и Reference Paths проекта сохраняются в папке проект.csproj файл.файл пользователя, а не проект.файл csproj.

5 ответов


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

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

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

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

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());
    }
}

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

взгляните на: Microsoft.Строить.Пространство Имен Оценки, существует некоторая полезная информация о том, как загрузить файл csproj, а затем как его изменить. См. также Проект Класс.


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

чтобы задать путь ссылки в Visual Studio:

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

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

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


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

    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.Взаимодействие.dll из \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\ и скопировал его в мою папку \ bin\debug\ добавив, что в качестве ссылки внезапно воспроизвел ваш сценарий> я получил include, но не hintpath.
Затем последний тест: я переименовал VsWebSite.Взаимодействие.dll в xxVsWebSite.Взаимодействие.dll и включил эту dll. Вдруг hintpath снова добавил!

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

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

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

любопытно о ваших результатах :)


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