Using CLR managed classes in unmanaged win32 applications
.Net has special code to expose managed classes as COM objects. Normally to use a .Net assembly through COM you need to register the assembly using REGASM.EXE. Windows win32 side-by-side has special provisions for registration-free accessing of .Net classes using COM.
A new manifest entry, <clrClass> declares the name, class ID and, optionally, ProgID of a class that can be accessed from Win32 through COM. The CLR assembly that implements the class is found by CLR (fusion) using the manifest identity from the Win32 manifest. This means that the CLR assembly identity (name, version and public key token) must be the same as the corresponding values in the win32 manifest. It also means that if the manifest is not embedded in the DLL, the search will fail if the DLL is found sooner then the manifest file. Note that if both are in the same folder, the DLL is checked before the manifest. The side effect of this is that if a CLR assembly is installed in GAC (Global Assembly Cache), Win32 will never find the manifest unless it is installed as a shared Win32 assembly (in %systemroot%\WinSxS).
Microsoft's recommendation for preparing CLR-managed classes for use with COM is to embed the win32 manifest in the DLL as a win32 resource. See MSDN for details... To embed CLR manifests in .Net DLLs during a Manifest Maker build, select the Embed CLR manifests in DLLs... option in the Build Options dialog.
However embedding CLR manifests is not always practical. For example if the DLL is strongly named modifying the module invalidates the signature and requires that the DLL be re-signed using the original certificate.
To use A CLR managed class using an external manifest follow these configuration guidelines:
- Build a CLR class manifest for every CLR-managed assembly you need to use.
- Place the manifest ahead of the DLL in the search order.
- Reference these manifests in your application manifest.
- Build type libraries (TLBs) for those CLR assemblies that need it.
- Add TLB references to either the CLR class manifests or to any other win32 manifest used by the application
Manifest Maker supports building win32 manifests for CLR classes in both Automatic and CLR (.Net) Class Win32 Manifest build types. In both cases, if embedding CLR manifests is turned off, each CLR assembly DLL is placed in a subdirectory of the target directory and the corresponding CLR manifest is written to the target directory. This is different from Win32 assemblies where the manifest must be in the same folder as all files referenced in that manifest.
Note that if embedding CLR manifests is turned on, Manifest Maker places the DLLs in the target directory, not in a subdirectory. This simplifies the final file layout and helps resolve interdependencies among multiple CLR DLLs in the project.
Use the Automatic build type if you are building manifests for a Win32 program. Use the CLR (.Net) Class Win32 Manifest build type when you need to use the CLR class manifest for a more elaborate configuration.
You should only build manifests for those assemblies you want to access from win32 code using COM. Any other assemblies need to be located where CLR (.Net) expects to find them. Specifically any assemblies needed by assemblies in your project must be manually placed in appropriate folders. This usually means in the subfolder created by Manifest Maker for the CLR DLL used in the project.
Suppose you have the following files:
- sample.exe - your win32 (not managed) program.
- example.managed.class.dll - the managed (.Net) assembly you need to use with the above program.
- helper.managed.code.dll - another .Net DLL used by the above example.managed.class.dll.
You should add the first two files to the project and choose Automatic build. The build may fail with a message that the example.managed.class.dll could not be loaded because dependent assemblies are missing. Copy the helper.managed.code.dll to the example.managed.class subdirectory created by Manifest Maker for the example.managed.class.dll. Click the Build button again - this time the build succeeds. Also see fusion logs below.
Win32 Manifest Search Order
|(application directory)\(assembly directory)||.DLL|
|(application directory)\(assembly directory)||.MANIFEST|
For more details on assembly search sequence read Assembly Searching Sequence on MSDN...
Default CLR Assembly Search Order
|(application directory)\(assembly directory)||.DLL|
|(application directory)\(assembly directory)||.EXE|
For more details on configuring CLR assembly loading read Runtime Settings Schema on MSDN...
Please see Assembly Search Sequence Changes in Windows 7 for information on new, undocumented, manifest search behaviour of Windows 7.
The CLR (.Net) loader, called Fusion, can write detailed logs of CLR assembly search and loading. This is an invaluable tool for diagnosing assembly loading problems. To turn on Fusion logs:
- Create a directory where you want the logs written. For example C:\Temp\FusionLogs.
- Add the following entries to the registry:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion] "ForceLog"=dword:00000001 "LogResourceBinds"=dword:00000001 "LogFailures"=dword:00000001 "LogPath"="C:\\Temp\\FusionLogs"
- Run the program you are diagnosing. This also works if you are getting errors during builds of win32 manifests for CLR classes. In the example above you will get the details on where did CLR look for helper.managed.code.dll.
- Run FusLogVW.exe - Fusion log viewer (included with .Net Framework) to read the logs.
- If you have problems running Fusion log viewer, just open C:\Temp\FusionLogs with Windows Explorer and navigate to the various subfolders to locate the logs you need. These are HTML files that are easily viewed with your favourite web browser.
- Remove the debugging entries from the registry to avoid the cost of writing
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion] "ForceLog"=- "LogResourceBinds"=- "LogFailures"=- "LogPath"=-