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:
- в обозревателе решений выберите проект.
- в меню проект выберите команду свойства.
- Щелкните Ссылочные Пути.
- в текстовое поле папка укажите путь к папке, содержащей сборки. Чтобы перейти к папке, нажмите кнопку (...).
- Нажмите Кнопку Добавить Папку.
вы должны сделать то же самое из объекта автоматизации
Дайте мне знать, если это помогает
трудно отказаться от хорошего вызова ...
Я не там, но я думаю, что у меня есть некоторые приличные намеки, чтобы продвинуть это вперед.
Во-первых, я создаю миниатюрный тестовый аддин для воспроизведения вашей проблемы и .. Я провалился!
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 тоже был.