views:

151

answers:

2

I have a Visual Studio 2008 project that I "upgraded" to Visual Studio 2010. Since the upgrade I have been having a lot of problems with the project (a project that was and still is trooper in 2008 I might add).

The first problem is that building the main executable locks the executable, causing further rebuilds to fail. This is described in a related question: http://stackoverflow.com/questions/2002273/visual-studio-locks-output-file-on-build where I picked up the workaround:

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

Except this workaround works exactly once. The .locked file then is locked by devenv.exe as well and must be moved. I have been working around this by adding .1.locked, .2.locked, etc. The only time that the locks are removed so the files can be deleted is on shutdown of devenv.exe (it takes a few seconds after the UI vanishes, then the files can be removed).

The fact that the debugger does not have to be used to cause this problem points to a pretty serious issue with the 2010 build system.

Some theories I think I can discount:

  • Antivirus or other background tasks: if this was a problem it would seem 2008 would fail. However, being a completest I removed the avast! system entirely with no luck.

UPDATE: This project has the same symptoms on a machine with no antivirus and no backup utility. The machines in the office are running XP SP3 32bit, my local machine is Windows 7 64 bit. This appears to be OS independent.

  • The debugger is locking the file: all that is required to reproduce this is repeating the build process without debugging. ProcessExplorer shows devenv.exe is the holder of the locks, not the vshost and killing the vshost.exe doesn't remove the locks anyway.

I have a secondary problem that starts to occur once the files get locked: the form designers stop loading with a "can't find assembly" error. I suspect these are related to the earlier locking issue as the designers fire right up prior to a build, but making any changes and rebuilding will cause all the designers to collapse with that error (even ones I have open and as the current view).

It is pitiful to watch a form close to the white error screen just because you changed "dummy=1" to "dummy=2" where "dummy" does absolutely nothing but force a recompile in a completely unrelated assembly.

Update: I have tried a few more remedies: Enable .NET source stepping is not checked, so that isn't the issue. Removing the .SUO (solution user options) simply works for as long as a restart would normally remove the problem (two builds: the first because there is no locked file and the second because there is one, but it can be renamed by the script).

Error   28  Unable to copy file "obj\Debug\PolicyTracker3.exe" to "bin\Debug\PolicyTracker3.exe". 
The process cannot access the file 'bin\Debug\PolicyTracker3.exe' because it is being used by another process.  
+1  A: 

There's a known file handle leak bug in the .NET framework source stepping feature. Easy to avoid by turning the option off in Tools + Options + Debugger. That is however unlikely to be your problem if you never got the debugger going.

It is quite unclear why Visual Studio would be interested at all in the build output, let alone load and lock it. Maybe you opened the .exe once? Delete the hidden .suo file in the solution directory to be sure. There isn't any feedback report on connect.microsoft.com that matches your issue, I'd recommend you start your own one. They'll need something reproducible for them to take a look at it, make sure you include a sample project that exhibits this behavior.

Hans Passant
Do you have a reference to the source stepping problem? I found reference to it regarding 2008, but they claim it fixed in 2010 (which would be exactly backwards from my experience). Not that it is of primary concern with the build issue, but I'm just curious for details.
Godeke
I found it while browsing connect reports. It was a 2010 issue. Since lost the link, I'm sure you can find it back.
Hans Passant
Strangely, nuking the .suo file seems to have made some kind of difference. I'm going to assume that the conversion corrupted it somehow (although I would have expected it to be deleted to be honest in the conversion).
Godeke
Well, no, it fixed it for a while (even over several debugs), and now the problem is back same as originally stated. I have searched connect and I can't find the reference to the leaked files issue, but perhaps the problem is related in that if any debugging was done in the past the suo is updated with something that then triggers the build problem?
Godeke
I can't look over your shoulder from here to be able to see what might cause this. Restating: start your own feedback report.
Hans Passant
Please unmark my answer, it was not the correct one.
Hans Passant
+3  A: 

Until a patch rolls around for this, I have the following workaround. Simply call using something like "C:\MyBin\VisualStudioLockWorkaround.exe" "$(TargetPath)" (replacing MyBin with the location you place the executable).

Create this as a C# console application and is used in the Pre-Build section in the same way the original pre-build rename was (see the top of the original question for details).

 using System;
 using System.IO;

 namespace VisualStudioLockWorkaround
 {
  class Program
  {
   static void Main(string[] args)
   {
    string file = args[0];
    string fileName = Path.GetFileName(file);
    string directory = Path.GetDirectoryName(args[0]);
    if (!Directory.Exists(directory)) //If we don't have a folder, nothing to do.
    {
     Console.WriteLine(String.Format("Folder {0} not found. Exiting.", directory));
     return;
    }
    if (!File.Exists(file)) //If the offending executable is missing, no reason to remove the locked files.
    {
     Console.WriteLine(String.Format("File {0} not found. Exiting.", file));
     return;
    }
    foreach (string lockedFile in Directory.EnumerateFiles(directory, "*.locked"))
    {
     try //We know IOExceptions will occur due to the locking bug.
     {
      File.Delete(lockedFile);
     }
     catch (IOException)
     {
      //Nothing to do, just absorbing the IO error.
     }
     catch (UnauthorizedAccessException)
     {
      //Nothing to do, just absorbing the IO error.
     }                                        
    }

    //Rename the executable to a .locked
    File.Move(file, Path.Combine(directory, String.Format("{0}{1:ddmmyyhhmmss}.locked", fileName, DateTime.Now)));
   }
  }
 }
Godeke
Revised to include UnauthorizedAccessException. Curious if this is just what a locked file throws (obviously I was expecting the IOException instead) or if it points to part of the problem?
Godeke