Visual Studio 2010 DTE:如何使添加的 DLL 引用绝对且不复制
摘要:
当您添加特定 DLL 时,我们需要使用 DTE 复制“添加引用”对话框的行为(它向 CSProj 文件中的引用添加提示路径条目)。
**注意:我这里还有另一篇相关但不重复的帖子:https://stackoverflow.com/ questions/6690655/visual-studio-2010-add-in-how-to-get-a-references-hint-path-property 另请阅读该内容有关此问题的更多信息。我现在已经添加了一笔不错的赏金来获得这个问题的答案,并且很乐意对任何像样的答案进行投票:)*
到目前为止的故事:
我正在使用 DTE 以编程方式将项目引用转换为直接 DLL 引用。
假设我有一个简单的解决方案,其中的 Project2
(父 项目)引用了 Project1
(子 项目) ),我进行如下更改:
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 引用,而不需要复制并引用该 DLL?
我尝试在“添加”之后添加 dllReference.CopyLocal = false;
,但是除了设置标志之外没有任何区别。创建后似乎没有修改路径的选项。
更新:我还尝试以编程方式从 Project2 中删除对 Project1 的任何构建依赖项,但这没有效果。
下面是 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 属性的句柄)?
更多信息(2011 年 7 月 20 日):
来自 下面的 Muse VSExtensions 不会影响相关 DLL,因为已从 DLL 的项目 BIN 到父项目的 BIN 文件夹。父项目不会费心使用引用路径,因为它的输出文件夹中已包含子 DLL。
此外,项目的参考路径
会保存到project.csproj.user 文件,而不是project.csproj 文件。
Summary:
We need to duplicate the behaviour of the Add Reference dialog, using DTE, when you add a specific DLL (it adds a Hint path entry to the reference in the CSProj file).
**Note: There is another related, but not duplicated, post from me here: https://stackoverflow.com/questions/6690655/visual-studio-2010-add-in-how-to-get-a-references-hint-path-property Please also read that one for more information about this issue. I have now added a decent bounty to get an answer to this and will happily spread up-votes over any decent answers :)*
The story so far:
I am converting a project reference to a direct DLL reference programmatically using DTE.
Assuming I have a simple solution with a Project2
(the parent project) which references a Project1
(the child project), I make the change like this:
project1Reference = FindProjectReference(project2.References, project1);
project1Reference.Remove();
Reference dllReference = project2.References.Add(project1DllPath);
where project1DllPath refers to the "c:\somewhere\Project1\Bin\Debug\Project1.dll"
file.
The problem I cannot yet solve is that the new reference is not to"c:\somewhere\Project1\Bin\Debug\Project1.dll"
but instead points to"c:\somewhere\Project2\Bin\Debug\Project1.dll"
(and the file is copied there).
If I add the DLL directly/manually using the Add Reference menu, it does not do this copying.
How do I add a DLL reference to an existing project's DLL without it taking a copy and referencing that instead?
I have tried adding dllReference.CopyLocal = false;
after the Add but aside from setting the flag it made no difference. There appear to be no options to modify the path after creation.
Update: I have also tried programmatically removing any Build dependency on Project1 from Project2, but that had no effect.
Below is the difference between the csproj files:
As a project:
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<Project>{86B3E118-2CD1-49E7-A180-C1346EC223B9}</Project>
<Name>ClassLibrary1</Name>
</ProjectReference>
</ItemGroup>
As a DLL reference (path was lost completely):
<ItemGroup>
<Reference Include="ClassLibrary1, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
...
</ItemGroup>
As a manually referenced DLL:
<ItemGroup>
<Reference Include="ClassLibrary1, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\ClassLibrary1\bin\Debug\ClassLibrary1.dll</HintPath>
</Reference>
...
</ItemGroup>
It looks like being able to specify the hint path for the DLL reference is the key. How do you set a hint path on a DLL reference (assuming you only have a handle to the Reference property)?
More information (20 July 2011):
The suggestion from Muse VSExtensions below does not impact the DLLs in question, as a copy has already been made from the DLL's project BIN to the parent project's BIN folder. The parent project does not bother to make use of the reference path as it already has the child DLL in its output folder.
Also the Reference Paths
of a project are saved to the project.csproj.user file and not to the project.csproj file.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我确信这是 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(...”) 行并始终添加提示可能会很有用。我仍在调查此案,因此任何其他 -嗯,欢迎对代码进行提示或改进。
I'm convinced that this is a new bug/feature in VS 2010 because I have an add-in that started showing similar behaviour a couple of days ago after I migrated it from VS 2008... Basically, if you add a reference to anything within VS's assembly search path, it will be added without the path hint.
I managed to find other VS add-ins that solved this problem (Power Tools, NuGet among others), and they all seem to use MsBuild. I don't know if MsBuild raises resource usage much - I myself haven't seen too big a slowdown, possibly because References.Add() is very slow to start with. But note that to get an instance of MsBuild project, a method called "GetLoadedProjects" is used, which may mean that it works on data already present in memory.
Below is the code I used to fix my add-in, it's a simplified version of what I found on the net... Essentially, the idea is to add the reference as usual, then use MsBuild to set the path hint. Setting the hint is a trivial operation, but finding the instance of the MsBuild project item to add the hint to is incredibly complicated. I tried to hack an alternative using MsBuild only, but ran into other problems... This one seems to work.
One other thing that may be of interest here: the code contains a sort of optimization - it doesn't add the hint to the new reference if the reference's path is equal to the path we wanted to add. This is good enough for the case in question, and detects correctly when VS decides to use the dll from the output folder instead of what we told it. But when I tried to add a reference to the dll already in the output folder (I use a single output folder for many related projects), the add-in didn't set the hint path and project seemed to switch to using some other dll in the path (in my case the one from its PublicAssemblies folder)... So it may be useful to remove that "if (!newRef.Path.Equals(..." line altogether and add the hint always. I'm still investigating this case, so any additional - uhm, hints or improvements of the code are welcome.
这个问题是否必须仅使用 DTE 来解决?您可以使用 MSBuild 自动化来执行此操作...它具有可以解析 csproj 文件内容的类。
看看:
Microsoft.Build.Evaluation 命名空间,
有一些关于如何加载 csproj 文件以及如何更改它的有用信息。
另请参阅项目类。
Does this have to be solved using only DTE? You could use MSBuild automation to do this... it has classes that can parse the contents of a csproj file.
Take a look at:
Microsoft.Build.Evaluation Namespace,
there is some useful information on how to load the csproj file, and then how to change it.
See also the Project Class.
要解决此问题,您需要从 DTE 将引用路径添加到项目属性。
要在 Visual Studio 中设置引用路径:
您必须从自动化对象中执行相同的操作
让我知道是否有帮助
To solve this problem you need to add a reference path to the Project properties from DTE
To set a reference path in Visual Studio:
You have to do the same from the automation object
Let me know if it helps
很难拒绝一个好的挑战......
我不在那儿,但我想我有一些不错的提示来推动这一进程。
首先,我创建了一个微型测试插件来重现您的问题,然后..我失败了!
这是来自我磁盘上某个位置的随机 dll。该 dll 未签名,最终出现在我的 csproj 中(正是您想要完成的任务):
然后我注意到您的 dll 已签名。这也没有什么区别。我做的下一个测试是复制一些标准的 MS dll。我从 \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\ 中选择了 VsWebSite.Interop.dll 并将其复制到我的 FromFolder\bin\debug\ 添加作为参考突然重现了您的场景>我得到了包含,但没有得到提示路径。
然后是最终测试:我将 VsWebSite.Interop.dll 重命名为 xxVsWebSite.Interop.dll 并包含该 dll。突然又添加了提示路径!
将所有这些和您的描述结合在一起,我的猜测是,在添加引用时,VS 首先查看是否可以在其当前搜索位置(GAC、项目文件夹、路径(?)、..)中找到引用的 dll,如果是,则没有提示路径额外。如果找不到,则需要并添加提示路径。
要查看这个理论是否成立,您可以做两个测试:
对你的结果感到好奇:)
Hard to reject a good challenge ...
I'm not there but I think I have some decent hints to move this forward.
First off I create a miniscule test addin to reproduce your problem and .. I failed!
This is a random dll from somewhere on my disk. The dll is unsigned and ended up in my csproj as (just what you want to accomplish):
Then I noticed you dll was signed. That did not make any difference either. The next test I did was copy some standard MS dll. I picked VsWebSite.Interop.dll from \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\ and copied it to my FromFolder\bin\debug\ Adding that as a reference suddenly reproduced your scenario> I got the include but not the hintpath.
Then the final test: I renamed VsWebSite.Interop.dll to xxVsWebSite.Interop.dll and included that dll. Suddenly the hintpath was added again!
Combining all this and your description together my guess is that when adding a reference VS first looks if the referenced dll can be found in it's current search locations (GAC, Project folder, path(?), ..) If so then no hintpath is added. If it can't be found then a hintpath is required and will be added.
To see if this theory holds up you could do two tests:
Curious about your results :)
我最近在 Visual Studio 2010 中添加 dll 引用时遇到了问题,我无法让它添加 HintPath,这导致了 TFS 构建的问题。我注意到几周前安装的 Productivity Power Tools 插件更改了添加参考对话框。我从“工具”菜单中关闭了该附加组件的“可搜索添加引用对话框”,在重新启动 Visual Studio 2010 后,我再次感到高兴 - 我能够添加引用,这次 HintPath 也在那里。
I had an issue recently with adding a dll reference in Visual Studio 2010, I couldn't make it add the HintPath, which caused an issue with the TFS build. I noticed that the Productivity Power Tools add-on that I installed a few weeks ago, had changed the add reference dialog. I switched off the "Searchable Add Reference Dialog" of the add-on from the Tools menu and after restart of the Visual Studio 2010 I was happy again - I was able to add the reference and this time the HintPath was there too.