I have a custom MSBuild task(resides in assembly A) to build a custom project type(let's call it 'TestAppContent'). 'A' references another assembly 'B' that is currently under development.
To test 'B', I use a test program, TestApp. TestApp depends on TestAppContent getting build using our custom task.
The problem is that after the task is loaded, 'B' assembly is locked by MSBuild or VisualStudio process as the assembly that contains the task('A') has a reference to it.
As I can't simply 'unload' an assembly and using separated AppDomain doesn't work, how can I stop this lock?
I know that Microsoft XNA can do this as you can supply custom assemblies to the build process and they are released after it so you can rebuilt those custom assemblies.
The only way is to use an AppDomain and activate the Shadow Copy on it. I don't think you can activate shadow copy on current AppDomain, but you can try (see question here)
Or you can manually copy the dll elsewhere and load it (programmatically) so that the original dll will not be loaded and will remain unlocked. But you can't load the same dll twice... so you'll need a separate AppDomain if you want to unload and load a new version (or you restart your program)
EDIT:
You can also use AppDomain.CurrentDomain.AssemblyResolve to intercept when you program try to load a dll. There you can copy it elsewhere and load this copy.
I think it won't help you that much since you're trying to achieve it automatically but one manual way to achieve this i found out was using sysinternals ProcessExplorer to kill the specific process using the dll. But killing doesn't seem to harm VS2013, which makes this is a workaround without the need to restart MSVS.
In this case my Visual Studio process instantiated an MSBuild instance which previously created the DesignLibrary assembly - now being locked, which the project SomeLibrary uses right within the build only. At this point it is not possible to rebuild the DesignLibrary assembly without killing the MSBuild task holding the lock.
I would like to have the MSBuild.exe checking during the build if it tries to rebuild a file created by itself, or maybe visual studio intervening this messy situation. Just another thought: Maybe it might be possible to inspect the process tree and kill the process automatically, like i did manually. A very hacky workaround ;)
One way I usually solve this is by having two solutions. The first builds the Tasks and then I hook it up to launch devenv.exe to load the second .sln when I press F5.
The second solution consumes the task built in the first causing it to be loaded into the second devenv.exe process. When you stop debugging the second Visual Studio will close and the assembly with the build task will be released.
Related
I am writing a library add-in that uses COM Interop and I am having problems during the clean and rebuild tasks. Visual Studio 2019 is setup to run a external program to debug and runs the .dll registration after the build using regasm to write registry values for the external program. I am using the "Register for COM interop" option.
This is causing problems during the clean/rebuild tasks. If I run a clean/rebuild on the solution I receive Access to the <dllPath> path is denied but if I run a clean on each individual library or run a clean twice (first time gives errors, second time works) things seem to work but leaves the msbuild and VBCSCompiler services hung up after shutting down VS.
However if I unregister the library via the command line using C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm /unregister <dllPath> before building the project, VS throws an error saying that the registry key doesn't exist, VS thinks it needs to unregister the library but the clean works as expected and removes the files in bin/Debug.
To run the registration I have:
<PropertyGroup>
<FrameworkSDKPath>
$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework#InstallRoot)
</FrameworkSDKPath>
</PropertyGroup>
<PostBuildEvent>
"$(FrameworkSDKPath)v4.0.30319\regasm" /codebase "$(TargetPath)"
</PostBuildEvent>
If I don't have the post build event it only registers the .dll in the GC but doesn't call the methods decorated with [ComRegisterFunction] and the external program doesn't recognize it. There are a couple of problems besides not deleting the files, if the decorated [ComUnregisterFunction] is not called (VS doesn't call this when cleaning/rebuilding) it will leave artifacts within the external programs registry entries, but it clears the GC entry.
Is there a way to get all this to sync up or do I need to revert to a total manual build process to take care of the registration? Is there an option to tell VS to call the register/unregister functions during the build/clean? Am I missing a step or a configuration setup?
As Simon pointed out, I didn't need to have the "Register for COM interop" option enabled since I was calling RegAsm.exe in the build, disabling this option allowed the files to be updated without any problems.
I downloaded a package from SourceForge, PlanEph, which has 64 and 32 bit DLLs for C#. I got the 32 bit included C# demo to work by putting the DLL in my bin/Debug directory (I'm using Visual Studio 2015 Community) and adding the DLL as a reference.
Then I tried to make my own version of the demo in a separate solution, and got the System.DllNotFoundException. Various experimentation lead me to believe I can't have two identical namespace names anywhere in my Visual Studio installation, so I erased everything and started over.
I made a directory C\GJAbin, put the DLL in it, and added it to the system Path variable. I also put a helloWorld type program in that dir and executed it from the command line to verify the directory really was in the path. Then I recreated the demo solution, added the DLL as a resource, and built the solution "successfully". Then I ran it and got the System.DllNotFoundException.
So I can't understand why the DLL is being found when compiling but not at run time.
Go to project settings, go to "publish" tab and on the top most button (labeled something like "application files"). Chose "Show all files" checkbox if you don't see your DLL. Set the DLL's publish status to "Include" (NOT "Include (Auto)"!!) and publish it again.
Now the DLL should be inside the publish folder.
So I can't understand why the DLL is being found when compiling but not at run time.
Locating the assembly at compile time is done differently (by MSBuild) than at runtime (by the CLR).
At compile time, MSBuild has specific search paths that it knows about, or in most cases like this, there will be something in your project file telling MSBuild where to look for the file. Usually the <Reference> has a <HintPath>.
At runtime, the CLR will attempt to find the assembly from its own set of well-known paths. It will look in your app's config file (if applicable), then in the Global Assembly Cache (GAC), then in your app's root directory. Much more detail on this is available here.
You can tell MSBuild to copy the reference to your build output directory (usually the same as your app root directory when running). In VS, you can do this by selecting the reference and looking at the Properties tool window (or press F4 by default). Set the CopyLocal state to True. In the project file, this will add a <Private>True</Private> on the <Reference>.
You can also add the assembly to the GAC using the gacutil tool, but this does make it harder if you want to share your app with others. Usually it's preferable to keep a copy in your app root directory.
If it's still not working, you can also see the log for how the runtime is trying to find this assembly. The fuslogvw.exe tool in the Windows SDK (you can run it from the VS command prompt and it will be on the %PATH%) allows you to enable logging for assembly loads. You do need to be able to run this as an administrator to configure the setting.
As you can see in the screenshot, you can either log the results in the exception (so that you can see it while debugging), or you can log it to a file on disk (so you can see it whenenver).
The problem turned out to be an unfortunate interaction among the way the author chose names and the way Visual Studio displays information and error messages. The author created a c# dll Astronomy.PlanEph32.dll containing a namespace PlanEph32, which which was really just a wrapper for the c dll PlanEph32.dll. So all the error messages about not being able to load PlanEph32.dll were referring to not finding the c dll; the c# dll was being found just fine.
When I try to run the project it says:
Error while trying to run project:could not load file or assembly 'Project.exe' or one of its dependencies.
The module was expected to contain an assembly manifest.
When I ran the exe from the debug folder I got this error:
application unable to start correctly (0xc000007b)
I also reinstalled Visual Studio but it doesn't seem to work!
The module was expected to contain an assembly manifest
It is a low-level assembly loading problem. The CLR has located a file with the right name but when it tries to load the assembly, it finds out that the file doesn't contain a proper manifest. A .NET assembly must contain a manifest, it contains metadata that describes the assembly, listing the types in the assembly, etc.
If you have no clue what EXE or DLL might be the troublemaker then you can use the Fuslogvw.exe utility:
Start it from the "Visual Studio Command Prompt".
Click the "Settings" button and click the "Log binding failures to disk" radio button.
Switch back to VS and start the program and wait for the exception to occur.
Back to Fuslogvw, click the "Refresh" button and double-click the added entry.
It shows you the file it found.
Several possibilities, a common one these days is to trying to load a .NET 4 assembly with an EXE that asked for CLR version 2. That requires an app.exe.config file that forces CLR 4 to be used.
In my case I just change Target Framework(.Net Framework 4) in Project Properties. It solves the problem.
I have the same problem when I use Vs2012 utimate to publish Asp.net Mvc4, then upload dll to server.
I fixed it by build code as Release mode then upload all dll in bin folder to server.
IN my case it get fixed by just going to project properties and set-->startup object projectname.program and build->platform target--> x86.
i just resolve this by problem by restarting System as well in project properties i set to multi users as well in combo box start option.hope this will help u.
0xc000007b is "STATUS_INVALID_IMAGE_FORMAT". From experience, this points me to the project properties.
A few things worth checking out:
Check to see if all the build options are set to either x86 or x64, depending on your system architecture, or AnyCPU.
If you're using dlls, consider whether they were compiled for your target architecture or not. If not, then recompile them accordingly or get them in the right version from wherever you got them.
Finally, check if your project assembly and loaded assemblies have different names. That seems to make things go boom as well.
I have a weird situation with some code that I inherited at work. Their application is a multi-project solution, with several of the solutions being (code) pieces of the MS Enterprise Library (not sure which version).
They also have an existing C++ (unmanaged) application which has a bunch of DLLs. One of these DLLs is built in a separate solution, both in 64-bit and 32-bit flavours.
The main application has a reference to this DLL, and calls a couple of static functions (I can see intellisense, even). I can compile and build the main application EXEs, but when I run it, I get an exception that this DLL from the unmanaged code (lets call it CPlusPlusCode.dll cannot be found:
FileNotFound Exception was unhandled: Could not load file or assembly 'CPlusPlusCode.dll' or one of its dependencies. The specified module could not be found.
I'm quite stumped, because I can compile the code, see intellisense for the imported classes, and dig into the DLL in the object browser. I even made sure there's a copy in the \bin\Debug folder (although I don't see why that would make a difference). This is for a Windows Forms application.
Also, if it matters, I had some build issues related to x86 vs. x64 for different projects; I think (hope?) that this is not related to that, but I solved that by using the Configuration Manager to build everything as x64.
Check the GAC, and if necessary you might need to add it or register the DLL there.
I had this problem with a project, it all works ok from Visual Studio and most of my times running the project locally on my machine. But because of the unmanaged code I needed specifically allow the project to be executed with correct permission levels.
So have a look in the manifest file, that enough permissions etc exist.
In my project I am loading a DLL using reflection and Assembly.LoadFrom(). This is a small DLL that is occasionally recompiled (from the source) dynamically during application execution.
Is there a way to unload the loaded DLL from the application so that I can reload it? I've tried reloading it, but I get an error:
file in use by another program
If the application that has the file open is a custom app, then you could modify it to load the DLL into another AppDomain. When you want to reload it, simply tear down that AppDomain and load the new DLL into the new AppDomain. I'd have a look at MEF (which does this) to see whether this might support your use case.
You can't. You have to kill the program. There is no way to unload an assembly in .Net.
Read these:
http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx
http://blogs.msdn.com/b/suzcook/archive/2003/07/08/unloading-an-assembly.aspx