Loading a 32-bit or 64-bit side-by-side COM DLL depending on the bitness with which the application runs - com-interop

I have a .NET application that uses a COM DLL, of which there is both a 32bit and a 64bit version. I have written two application manifests that make side-by-side COM interop work on either 32 Bit or 64 Bit. Here the 32-bit version:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity name="MyApp" version="1.0.0.0" type="win32" />
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="MyCOMDll_32.dll"
version="1.2.3.4"
processorArchitecture="x86"
publicKeyToken="0000000000000000"
language="*" />
</dependentAssembly>
</dependency>
</assembly>
However, maintaining two manifests leads to the loss of portability: you need to decide which version to use when you install the application. And the 64-bit application can no longer be run in 32-bit mode.
Is there a possibility to get the .NET application to load the correct 32-bit or 64-bit DLL depending on the bitness under which it runs?
I have tried using two dependency elements, one with <assemblyIdentity processorArchitecture="x86" .../> and one with <assemblyIdentity processorArchitecture="amd64" .../>, but that results in an application configuration error.
I'd be very grateful for answers.
Regards,
Moritz

I have not found a way to do this with an application manifest.Therefore, I dropped the application manifest in favor of a programmatic solution using the Activation context API.
This solution has been adapted from http://support.microsoft.com/kb/830033/en-us (where the field cookie must be an IntPtr not a uint).
I have replaced the inner part of the EnsureActivationContextCreated() method by
if (!contextCreationSucceeded)
{
string manifestLoc = Environment.Is64BitProcess
? "MyCOMDll_64.dll.manifest"
: "MyCOMDll_32.dll.manifest";
myComActivationContext = new NativeMethods.ACTCTX();
myComActivationContext.cbSize = Marshal.SizeOf(typeof(NativeMethods.ACTCTX));
myComActivationContext.lpSource = manifestLoc;
// Note this will fail gracefully if file specified
// by manifestLoc doesn't exist.
hActCtx = NativeMethods.CreateActCtx(ref myComActivationContext);
contextCreationSucceeded = hActCtx != Failed;
}

Related

Can't execute 64 bit version of my program

I'm just trying to build 64 bit version of an existing program (EXE with some dependent DLLs). Since it was very easy under Linux (just recompile it), I was optimistic it could be somehow similar under Windows. Unfortunately it is not...
After starting my newly compiled EXE, I get an error message
The application has failed to start because its side-by-side configuration is incorrect...
Tracking down the reason for it I made a SxS trace which shows following error message:
ERROR: Two assemblies have the same assembly name with different version.
Assembly 1: C:\Windows\WinSxS\manifests\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac.manifest.
Assembly 2: INFO: Manifest found at C:\Windows\WinSxS\manifests\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_fa396087175ac9ac.manifest..
So..what does this mean? And how can I resolve the problem? Installing the VS2010-redistributable package for x64 was not the trick, here installer complains about a newer version that is already installed...
The Manifest file mentions some X86...is this the reason? If yes: how can I find out on which X(& DLLs it still depends?
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="0.64.1.0" processorArchitecture="x86" name="Controls" type="win32"> </assemblyIdentity>
<description>wxWindows application</description>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
Your application manifest specifies x86 architecture and has two entries for comctl32.
You should specify x86 for your 32 bit build, and amd64 for your 64 bit build. And you should list comctl32 exactly once. For the dependent assembly architecture you can specify * if you wish, but personally I prefer to be explicit.

vb.NET DLL Registration Free COM with VB6

I'm trying to get the simplest Registration Free COM project to work in 64bit Windows7!
The COM component is also the simplest vb.NET DLL that works fine from the VB6 EXE when its registered.
Can anyone suggest why the manifests are not working please?
I have already tried to update any VB6 internal Manifest with mt.exe but the general error indicates that there is no internal manifest in Project2.exe
The VB6 program (Project2.exe) manifest is....
<assemblyIdentity name="Project2.exe" version="1.0.0.0" type="win32" processorArchitecture="x86"/>
<dependency>
<dependentAssembly>
<assemblyIdentity name="ClassLibrary1" version="1.0.0.0" type="win32"/>
</dependentAssembly>
</dependency>
</assembly>
And the DLL (ClassLibrary1.dll) manifest is.....
<assemblyIdentity name="ClassLibrary1" version="1.0.0.0" type="win32"/>
<clrClass
name="ClassLibrary1.Class1"
clsid="{D9531C2A-3822-4222-8D45-BC507FCDF5F3}"
progid="ClassLibrary1.Class1"
threadingModel="Both"/>
<file name="ClassLibrary1.tlb">
<typelib
tlbid="{DA8A00C1-1E14-4295-AEDE-F8F23DD8E43D}"
version="1.0"
helpdir=""
flags="hasdiskimage"/>
</file>
</assembly>
The manifests are correct, assuming that the Ids are correct. So your problem is something else. What error message do you get?
I employ RegFree Com succesfully and it has saved me countless headaches once you have the manifests right. I do not embed them. I use Side-by-Side Manifest Maker from Maze software for this, they are very helpful, very much worth the investment. I pasted the application manifest and the manifest of one of the dll's to give you a working example.
Filename=MyVB6App.exe.Manifest (Note the .exe. tag)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="MyVB6App.exe" version="2.8.0.127" type="win32" processorArchitecture="x86"/>
<description>Built with: Side-by-Side Manifest Maker (3.7.1.4434) (x86)</description>
<dependency>
<dependentAssembly>
<assemblyIdentity name="MyNetComWrapper" version="1.0.24.0" type="win32" publicKeyToken="6ABF096D69195FE6"/>
</dependentAssembly>
</dependency>
</assembly>
Filename=MyNetComWrapper.Manifest (Note the abscense of a .dll. tag)
<assemblyIdentity name="MyNetComWrapper" version="1.0.24.0" type="win32" publicKeyToken="6ABF096D69195FE6"/>
<description>Built with: Side-by-Side Manifest Maker (3.7.1.4434) (x86)</description>
<clrClass
name="MyComNetWrapper.SomeClass"
clsid="{A68F56A1-8425-3E06-BA83-856EC8422F5B}"
progid="MyComNetWrapper.SomeClass"
runtimeVersion="v4.0.30319"
threadingModel="Both"/>
<clrClass
name="MyComNetWrapper.SomeOtherClass"
clsid="{D5156DAF-0421-36AE-84B6-5D915068B2DC}"
progid="MyComNetWrapperc.SomeOtherClass"
runtimeVersion="v4.0.30319"
threadingModel="Both"/>
<file name="MyComNetWrapper.tlb">
<typelib
tlbid="{D189D056-66F1-4C01-8EB9-1F95BA11254A}"
version="1.0"
helpdir=""
flags="hasdiskimage"/>
</file>
</assembly>

Replacing Microsoft.VC90.CRT WinSxS policy file with local config file

On Windows XP, I have an .exe which runs with msvcp90.dll, msvcr90.dll, and Microsoft.VC90.CRT.manifest in my local application directory. I also have a policy file for these .dlls in C:\WINDOWS\WinSxS\Policies, which was installed by the Visual C++ 2008 SP1 Redistributable Package. I'd like to delete this policy file and use an app config file in my local directory instead. The policy file is:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32-policy" name="policy.9.0.Microsoft.VC90.CRT" version="9.0.30729.1" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30729.1"/>
<bindingRedirect oldVersion="9.0.30201.0-9.0.30729.1" newVersion="9.0.30729.1"/>
</dependentAssembly>
</dependency>
</assembly>
My config file is:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"/>
<bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30729.1"/>
<bindingRedirect oldVersion="9.0.30201.0-9.0.30729.1" newVersion="9.0.30729.1"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Dependency Walker reports side-by-side errors when using the config file instead of the policy file - what's wrong? Also, should the config file be named <application>.exe.config, or Microsoft.VC90.CRT.config?
(To clarify, no errors appear when using the policy file. However, the client here is not allowed to install the redistributable package.
The MSDN docs state that an app config file can redirect the application to use different versions of the same assembly (per-application configuration), and that it can override an existing policy (publisher configuration) file if needed. So I think it must be possible to use a local app config file, and that something in the file above is missing or incorrect.)
Your configuration data is under the <runtime> node. It should instead be under the <windows> node.
I have to caution that shipping application configuration files that contain binding redirects is highly discouraged and is inteded for system administrators dealing with an appcompat problem on the machines they adminster. Application developers should instead be authoring their applications to work with the latest revision of the specific version of the CRT they depend on and use the default global policy that ships with that version.
In fact, starting with Windows 2003, using binding redirects in an application configuration file requires an entry in the application compatibility database.
It is my understanding that the c runtimes cannot be redirected in this way for security reasons. Your options are to statically build the runtimes into your project or load the DLLs from your application directory with out the Side-By-Side system.

Howto: Multiple versions of msvcrt9 as private SxS assemblies?

I have a project that comprises pre-build Dll modules, built some time in the past, using Visual Studio 9.
The EXE of the project is built now, using SP1 of Visual Studio 9.
When we deploy the EXE we don't want to require administrative access, so the C-Runtime has been bundled into the root of the application. The Dlls: MSVCRT90.DLL and their Manifest: Microsoft.VC90.CRT.manifest
Now, the EXE and latest versions of the runtime manifests are all in agreement - the application manifest asks for 9.0.30729.1 of msvcrt.dll, and the crt-manifest contains the entries confirming that msvcrt90.dll is version 9.0.30729.1
Now, a problem. A 3rd party DLL library used by our application was linked against the original msvcrt90.dll version 9.0.21022.8 and has an internal manifest to this effect.
On our development PCs where both versions of the VS9 CRuntime have been installed the app works. On "fresh" PCs where we install the app for the first time - the DLL fails to load.
Now, I have some cheats I can do - one is to revert the app to 9.0.2 - get the 9.0.2 DLLs off the original source media. This is undesirable as 9.0.3 is preferable.
Or I try really hard to get a rebuild of the 3rd party library.
I am furthermore pretty certain that, on our development PCs, when the 3rd party library asks for the old dll it gets redirected to the new dll - they are binary compatible.
Application manifests and assemblies were meant to save us all from this kind of rubbish.
It must be possible to edit the assembly manifest files so that both the exe and dll can load.
I've never tried that but I think you can solve that with bindingRedirect in the manifest, I know that it works in the managed world.
See example (You will need to change the values for your version)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configuration>
<windows>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity name="Your.Application.Name" type="win32" version="9.0.0.0"/>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b" />
<bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30411.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.MFC" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b" />
<bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30411.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.MFCLOC" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b">
</assemblyIdentity>
<bindingRedirect oldVersion="9.0.20718.0-9.0.21022.8" newVersion="9.0.30411.0"/>
</dependentAssembly>
</assemblyBinding>
</windows>
</configuration>

How are an application's manifest-specified details used?

I am upgrading an unmanaged C++ application to use the XP/Vista style common controls by adding a manifest. According to MSDN's page on application manifests, you are required to specify the name and version in the manifest, and optionally the description:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.2.3.4"
processorArchitecture="*"
name="CompanyName.ApplicationName"
type="win32"
/>
<description>Application's description here</description>
</assembly>
How are these details used? There is a mention about backward compatibility being implied by having the same major and minor versions for assemblies, but this does not seem to apply to applications. I also haven't been able to see the name, version, or description specified by the manifest in the application's properties on Windows XP.
What effect does changing these have? Is it worthwhile to keep the version up-to-date?
I'd say its worth keeping them up to date. If for no other reason than you don't know what future tools might come along that make use of them. I'm not aware of any current uses for the assembly name, version, and so on specified in a native application's manifest. To populate the properties page on XP, you need to create a VERSIONINFO section in your resources.
For common controls to use the XP/Vista themes in a C++ application which does not link the manifest in (such as Visual C++ 6 apps), the following is a template you can use:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="Program Name"
type="win32"
/>
<description>Description of Program</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

Resources