Visual Studio在构建时锁定输出文件

81

我在VS 2010中有一个简单的WinForms解决方案。每当我构建它时,输出文件(bin\debug\app.exe)都会被锁定,并且后续构建失败,出现如下消息: "The process cannot access the file 'bin\Debug\app.exe' because it is being used by another process." 唯一的方法是在每次构建后重新启动VS,这非常麻烦。

我找到了这篇旧的博客文章http://blogs.geekdojo.net/brian/archive/2006/02/17/VS2005FileLocking.aspx-它似乎是一个很古老的问题。有人知道这里发生了什么,或者至少有一些解决方法吗?

更新

实际上我并没有运行这个文件,锁定发生在构建之后,而不是调试之后(即启动VS-构建-构建-失败!)。我尝试关闭杀毒软件,但没有帮助。

更新2

Process Explorer显示devenv.exe已加载该文件(在DLL中,而不是在句柄中)。似乎是在构建过程中出现了一些故障,阻止了卸载,但(第一次)构建完成时没有出现任何消息,除了"1 succeeded, 0 failed"。


我偶尔会遇到类似的问题;您使用Windows 7吗?在我的情况下,不是VS锁定了文件:我可以在资源管理器中直接删除它,然后构建运行就可以了。我注意到如果我在输出目录上打开一个资源管理器窗口,这个问题发生的频率更高。顺便说一下,没有使用病毒扫描程序。 - stijn
在使用 NUnit 进行 TDD 时,有时会在 Win7 上出现相同的问题,这非常令人恼火。 - Mathias
@stijn:不使用实时病毒扫描器?咕噜... - TheBlastOne
当我在调试单元测试并在VS完成测试执行之前停止代码时,这也会发生在我的电脑上,这种情况也发生在VS 2013上。如果我等待额外的几秒钟让VS卸载测试运行程序,就不会出现这种情况。 - StingyJack
也许这会有帮助: http://www.sevenforums.com/tutorials/194374-indexer-backoff-enable-disable-windows-7-a.html - Roi Shabtai
我遇到了这个问题,并通过这里的答案解决了它:为什么系统在应用程序退出后仍然会锁定可执行文件句柄?,但只有在问题是由系统引起时才有效。希望这能帮助到某些人。 - J3soon
16个回答

71

我曾经遇到相同的问题,但是找到了解决方法(感谢 Keyvan Nayyeri):

但是如何解决呢?针对不同类型的项目有不同的解决方式,但是我建议Visual Studio插件开发者可以在他们的项目构建事件中添加一些简单的代码来解决这个问题。

您可以将以下代码行添加到项目的预生成事件命令行中。

if exist "$(TargetPath).locked" del "$(TargetPath).locked"
if exist "$(TargetPath)" if not exist "$(TargetPath).locked" move "$(TargetPath)" "$(TargetPath).locked"

对我也有效。一直遇到这个问题。 - ritcoder
这对我很有效。根据Vladimir Datsyuk的建议,我尝试了%random%版本,但发现在我的情况下,唯一被锁定的文件是在启动VS后第一次构建的文件,因此它只需要运行一次即可。我使用的是VS 2013,也没有使用GUI设计器,只是一个有很多引用和T4模板项目的大型解决方案。 - Davos
5
我需要重命名PDB文件,因为它也被锁定了:如果存在"$(TargetDir)$(TargetName).pdb.locked",则删除它。如果存在"$(TargetDir)$(TargetName).pdb"但不存在"$(TargetDir)$(TargetName).pdb.locked",则将其移动到"$(TargetDir)$(TargetName).pdb.locked"。 - Tobias J
对我也适用(Visual Studio 2013)。谢谢。 - Anonymous
仍在使用VS2017工作。令人惊讶的是,这个问题在VS2017中仍然存在! - Carvo Loco

24

这不是病毒问题,而是Visual Studio 2010的一个bug。似乎这个问题与使用Visual Studio GUI设计器有关。

解决方法是在预构建事件中将锁定的输出文件移动到另一个临时文件中。最好随机生成临时文件名。

del "$(TargetPath).locked.*" /q 
if exist "$(TargetPath)"  move "$(TargetPath)" "$(TargetPath).locked.%random%"
exit /B 0

如果使用固定的临时文件名,你只会推迟锁定:

这种解决方法只能起到一次作用。

 if exist "$(TargetPath).locked" del "$(TargetPath).locked"
    if exist "$(TargetPath)" if not exist "$(TargetPath).locked" move "$(TargetPath)" "$(TargetPath).locked"

我也找到了一个解决方案,需要使用两个临时文件,可以正常工作2次。


1
我也遇到过这种情况,但只有在运行我的应用程序时才会出现。我怀疑是操作系统为了缓存或其他原因而监视可执行文件。此外,在我的情况下,似乎只发生在调用System.Reflection.Assembly.GetExecutingAssembly()的应用程序上。 - TheBlastOne
2
好的,看起来只有在最后一次运行调用System.Reflection.Assembly.GetExecutingAssembly时才会发生这种情况,或者 - 这是新闻 - 如果任何设计时组件的源代码(在组件工具栏中处于活动状态的任何设计时组件的源代码)在上次运行开始时在编辑器中打开并调用了System.Reflection.Assembly.GetExecutingAssembly。明白了吗? - TheBlastOne
1
我认为这个问题突然出现了...现在我浪费了30分钟的时间来构建项目设置..因为我遇到了锁定问题!我甚至没有运行应用程序.. - GorillaApe
1
这是我用过的Visual Studio输出文件权限问题的解决方法。 - GorillaApe
1
额外的pbd文件内容:del "$(TargetPath).locked.*" /q 如果存在 "$(TargetPath)" 则移动 "$(TargetPath)" 至 "$(TargetPath).locked.%random%" del "$(TargetDir)$(TargetName).pdb.locked.*" /q 如果存在 "$(TargetDir)$(TargetName).pdb" 则移动 "$(TargetDir)$(TargetName).pdb" 至 "$(TargetDir)$(TargetName).pdb.locked.%random%" exit /B 0 - Marv
这个问题在VS 2017中也存在,推荐的解决方案不起作用。 - gyousefi

6
我也遇到了这个问题。我的情况是:使用Windows 7(但在Windows XP上也可能发生),在处理WPF用户控件项目时,我一直都能够成功构建,但是当打开用户控件XAML文件后,我只成功构建了一次,然后所有文件都被锁定。
另外,我也注意到我是以管理员身份运行Visual Studio(Devenv.exe)。我开始以普通权限运行Visual Studio,问题就解决了! 如果这对你有帮助,请告诉我。祝你好运。

1
我在所有的VS11版本中都遇到了完全相同的问题,但是还没有找到解决方法(不幸的是,没有管理员权限也没有帮助)。有什么想法感激不尽! - Dan Nolan

4
我曾在贪婪的病毒扫描软件上看到过这个问题,或者是因为app.exe没有正确关闭。请确保进程已经停止运行。

3
您的机器上是否安装了病毒扫描软件?您能否看到任何正在持有文件句柄的进程(使用Process Explorer来查找)?
也许您的进程列表中出现了“app.exe”,即您最后调试的版本仍在运行?当您开发具有多个线程的应用程序时,如果您没有join它们中的所有线程,则可能会发生这种情况。

3

基于 Stackoverflow 上 Stormenet 的回答,我编写了一个小脚本,应该适用于所有情况。

以下是要放入“预先构建事件文本框”的代码:

$(SolutionDir)\BuildProcess\PreBuildEvents.bat  "$(TargetPath)"  "$(TargetFileName)"  "$(TargetDir)"  "$(TargetName)"

这是要复制到文件$(SolutionDir)\BuildProcess\PreBuildEvents.bat中的脚本(当然您可以修改此路径):

预构建事件

REM This script is invoked before compiling an assembly, and if the target file exist, it moves it to a temporary location
REM The file-move works even if the existing assembly file is currently locked-by/in-use-in any process.
REM This way we can be sure that the compilation won't end up claiming the assembly cannot be erased!

echo PreBuildEvents 
echo  $(TargetPath) is %1
echo  $(TargetFileName) is %2 
echo  $(TargetDir) is %3   
echo  $(TargetName) is %4

set dir=C:\temp\LockedAssemblies

if not exist %dir% (mkdir %dir%)

REM delete all assemblies moved not really locked by a process
del "%dir%\*" /q

REM assembly file (.exe / .dll) - .pdb file - eventually .xml file (documentation) are concerned
REM use %random% to let coexists several process that hold several versions of locked assemblies
if exist "%1"  move "%1" "%dir%\%2.locked.%random%"
if exist "%3%4.pdb" move "%3%4.pdb" "%dir%\%4.pdb.locked%random%"
if exist "%3%4.xml.locked" del "%dir%\%4.xml.locked%random%"

REM Code with Macros
REM   if exist "$(TargetPath)"  move "$(TargetPath)" "C:\temp\LockedAssemblies\$(TargetFileName).locked.%random%"
REM   if exist "$(TargetDir)$(TargetName).pdb" move "C:\temp\LockedAssemblies\$(TargetName).pdb" "$(TargetDir)$(TargetName).pdb.locked%random%"
REM   if exist "$(TargetDir)$(TargetName).xml.locked" del "C:\temp\LockedAssemblies\$(TargetName).xml.locked%random%"

3

我曾经遇到过同样的问题,后来发现只有在我打开一个窗体或用户控件并在构建前没有关闭它时,VS才会锁定exe文件。 解决方法很简单,我只需要在构建解决方案之前关闭所有的窗体/用户控件就可以了。


2

还有一个已知问题533411,自动更新构建版本号可能会导致锁定问题。Bug报告中的解决方法如下:

临时解决方法是在重新生成后禁用程序集版本更新。在AssemblyInfo.cs文件中,从AssemblyVersion属性中删除通配符,例如:
将这个:
[assembly: AssemblyVersion("1.4.*")]
[assembly: AssemblyFileVersion("1.4")]
替换为这个:
[assembly: AssemblyVersion("1.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]


2
我遇到了这个问题,并通过一些自定义代码解决了它。请参见这里:Visual Studio 2010构建文件锁定问题
按照接受的答案中所述编译实用程序并在构建步骤中引用它,以解决此问题。我仍然会在午餐时关闭VS 2010以清理早上的工作。
自定义代码的原因是经常推荐的解决方案只能起作用一次,然后重命名的文件也被锁定了,从而防止重命名。在这里,我们只是将数据时间信息附加到文件上,因此重命名的版本不会发生冲突。

0

对我有效的唯一方法是退出Visual Studio 2012,删除出现问题的项目的BIN和OBJ文件夹,然后重新打开Visual Studio。

问题解决了...直到下一次。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接