My .NET client application has a dependancy on another assembly. This dependancy is declared in an app.manifest
file:
app.manifest
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="Contoso.Frobber.Admin"/>
<!-- We have a dependancy on Grobber -->
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Contoso.Grobber" version="1.0.0.0" processorArchitecture="x86" />
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7-->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
</asmv1:assembly>
And then the project is configured to use our app.manifest
file. You specify the use of the custom app.manifest
under Project -> Application -> Resources:
And it all works
I have to be sure to place my other assembly in the same folder^1. For example:
Contoso.Grobber.manifest
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="Contoso.Grobber" version="1.0.0.0" processorArchitecture="x86" />
<file name = "Grobberify.dll">
<comClass
progid="Contoso.Grobberify"
clsid="{EB4B9718-0625-4505-BBF2-42CF7E94643E}"
description="Grobber system frobs"
threadingModel = "Apartment" />
</file>
</assembly>
So i have in my folder:
- SampleApplication.exe
- Contoso.Grobber.Manifest
- Grobberify.dll
And everything works. My application runs, and everything behaves correctly.
I can prove that my embedded manifest is being honored, because if i change my embedded manifest to require something called Contoso.Grobber asdfasfaraasdf:
<!-- We have a dependancy on Grobber -->
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="asdfasfaraasdf" version="1.0.0.0" processorArchitecture="x86" />
</dependentAssembly>
</dependency>
If run my application now, the Fusion loader will realize that there is no assembly called asdfasfaraasdf, and throw an error while loading:
The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log or use the command-line sxstrace.exe tool for more detail.
And if i put my dependant assembly back to the correct asdfasfaraasdf --> Contso.Grobber then everything works.
Except when debugging
For no particular reason, if i am inside the debugger then the fusion loader is not seeing my assembly manifest and it's dependant assemblies.
I can prove this by declaring in my assembly manifest that i depend on an assembly that doesn't exist (e.g. name="asdfasdfasf")
![enter image description here][3]
The application should fail to launch - but it launches! No matter what i do:
- use a fake assembly name
- delete the manifest of my depenent assembly
- delete the
.dll
of my dependant assembly
The application does not fail to launch. That means that whatever version of my executable that Visual Studio is running: it does not contain my embedded app.manifest
.
It's a problem because it's broken
You might think that having an application run is a good thing - i wouldn't want it to fail. That is wrong for two reasons:
- i want it to fail to launch if a required assembly is not present
- the dependent assembly contains required fusion information
The assembly i am loading is a COM dll. My .manifest
file contains much needed COM clsid
and filename information. When Visual Studio does not honor my application manifest, the Fusion loader will not see my registration-free COM objects:
<comClass
progid="Contoso.Grobberify"
clsid="{EB4B9718-0625-4505-BBF2-42CF7E94643E}"
description="Grobber system frobs"
threadingModel = "Apartment" />
</file>
Without this assembly comClass information, my .NET application cannot create the COM object while debugging:
[ComImport]
[Guid("EB4B9718-0625-4505-BBF2-42CF7E94643E")]
public class Grabasstic
{
}
IGrobberAss ga = (IGrobberAss)new Grabasstic();
It only happens when debugging
This failure of Visual Studio Community 2013 on Windows 7 64-bit with a 32-bit application, with a logged-in user who has no wallpaper configured only happens while debugging the application. If i run the SampleApplication.exe directly, the embedded assembly manifest is honored.
It might have something to do with the fact that Visual Studio doesn't debug
SampleApplication.exe
Visual Studio actually debugs an application called:
SampleApplication.vshost.exe
Or not. What do i know?
How do i make it work?
I know there's no solution. The volume of people on the planet who have any experience with registration-free COM is limited to:
It's safe to say that nobody actually read the entire block of "Research Effort" above. I'm also curious to see which users caught the easter-egg up there, as well as who will complain about too much research effort.
In reality, i know there is no solution. And while i can document the fact that this a problem, i am under no allusions that anyone can solve it. Which makes this entire 45 minute question a way for me to vent about unsolvable problems.
Bonus Reading
- Here's a guy who's embedded manifest is also being ignored. For him it is causing the application to not honor his
requireAdministrator
security entry - Manifest does not force Visual Studio 2013 to restart under Admin when running application in Debug mode
- App Manifest Ignored
- Visual Studio causing embedded assembly manifest to be ignored while debugging
The solution was to disable the Visual Studio hosting process from Project -> Project Properties:
Based on the MSDN documentation of the Hosting Process, it has no real value to developers, and can safely be turned off.