Skip to content

Latest commit

 

History

History
184 lines (152 loc) · 8.83 KB

hosting.md

File metadata and controls

184 lines (152 loc) · 8.83 KB

Managed Component Hosting

Overview

This document describes the behavior and implementation of WinRT.Host.dll, a native DLL which provides hosting for managed C#/WinRT runtime components. WinRT.Host.dll may be explicitly registered with an ActivatableClass manifest entry, or it may be renamed to support manifest-free activation. The details of how WinRT.Host.dll resolves and forwards activation requests are described below.

Conventions

To mininmize the need for explicit mapping data, a set of file naming conventions flows across the activation path, from class to host to target:

  • If the client is using manifest-free, the host name is derived from the class name. In turn, the target name is also derived from the class name.
  • If the client is using a manifest, the host name is explicitly specified and can be anything. The target name may then be derived from either the class name or the host name (if renamed).
  • If the host and target file names are fixed, a runtimeconfig.json entry can be used to provide an explicit mapping from class ID to target assembly.

Glossary

For brevity, the following terms are used throughout:

  • Client: the client of the activation request (caller of RoGetActivationFactory)
  • Target: the managed assembly implementing the runtime class
  • Class: the activatable runtime class
  • Host: an activation adapter that hosts a managed implementation

Probing

Probing is the algorithm for finding a target assembly, based on the runtime class name or the host file name. It is designed to maximize availability of the "good name" for a target assembly ("Acme.Controls.Widget.dll" in the examples below).

The target assembly may be discovered by:

  1. Class Name
    1. Probes the fully qualified class name, and successive dot-separated substrings of it, with and without a ".Server" suffix. The ".Server" suffix is included in the search to support different activation scenarios (see examples section).
    2. If the class name is "Acme.Controls.Widget", the following files are probed:
      1. Acme.Controls.Widget.Server.dll
      2. Acme.Controls.Widget.dll
      3. Acme.Controls.Server.dll
      4. Acme.Controls.dll
      5. Acme.Server.dll
      6. Acme.dll
  2. Host Name (if renamed from WinRT.Host.dll)
    1. Gets the host's file name via GetModuleFileName, short-circuits for "WinRT.Host.dll"
    2. Probes successive dot-separated substrings of the host file name, with a ".Server" suffix. The host name itself is skipped in the search.
    3. If the host name is "Acme.Controls.Widget.Host.dll", the following files are probed:
      1. Acme.Controls.Widget.Host.Server.dll
      2. (Acme.Controls.Widget.Host.dll is skipped)
      3. Acme.Controls.Widget.Server.dll
      4. Acme.Controls.Widget.dll
      5. Acme.Controls.Server.dll
      6. Acme.Controls.dll
      7. Acme.Server.dll
      8. Acme.dll

Host

From the activating client's perspective, WinRT.Host.dll is the implementation of the runtime class. Using the HostFxr library to host the CLR, it provides an adapter from native client code to the managed target assembly that actually implements the class. The host may be renamed from WinRT.Host.dll, to provide host-based probing to find the target assembly.

Exports

Per WinRT activation contract, the host exports:

  • DllCanUnloadNow
  • DllGetActivationFactory

To support forwarding scenarios, the host also exports:

  • DllGetActivationFactoryFromAssembly

DllCanUnloadNow may either:

  1. Unconditionally return false (this is the behavior of the .NET WinRT.Host.dll implementation)
  2. Track all loaded target assemblies, forward the call to them, and return false if any target does

Given that the host would likely use Reg-Free Activation, which does not support COM memory management, it makes little sense to adopt 2.

DllGetActivationFactory:

  1. Searches for target assembly based on:
    1. Class Name Probing (see above), or
    2. Host Name Probing (see above)
  2. If target found,
    1. Forwards to DllGetActivationFactoryFromAssembly with target name

DllGetActivationFactoryFromAssembly:

  1. Provides an 'overload' of DllGetActivationFactory that accepts an explicit target assembly
  2. Uses the HostFxr library to load the CLR and a managed WinRT.Host.Shim assembly:
    1. The behavior mirrors details in the .NET WinRT-activation spec
    2. A .runtimeconfig.json can be used to explicitly select a runtime version to address conflicts
  3. Binds to the shim's static factory method, WinRT.Module.GetActivationFactory
  4. Calls GetActivationFactory, passing the target assembly path and runtime class name
  5. GetActivationFactory:
    1. Uses reflection to find the target type
    2. Creates an IActivationFactory implementation for the target type
    3. Creates a CCW for the factory and returns it as an IntPtr
  6. The returned factory:
    1. Implements ActivateInstance by constructing the target type
    2. Creates a CCW for the factory and returns it as an IntPtr

Examples

Reg-Free Activation with Generic Host

Class Host Target
"Acme.Controls.Widget" WinRT.Host.dll Acme.Controls.Widget.dll
  1. Client registers class with generic host, via fusion or appx manifest:
    1. Fusion
    2. Appx WinRT.Host.dll
  2. Client activates class: RoGetActivationFactory("Acme.Controls.Widget")
  3. Host finds target via Class Name Probing (see above):
    1. "Acme.Controls.Widget.Server.dll",
    2. "Acme.Controls.Widget.dll"

Reg-Free Activation with Renamed Host

This example demonstrates how a target DLL that has already taken the "good name" can be supported, by using an appropriately renamed host.

Class Host Target
"Acme.Controls.Widget" Acme.Controls.Widget.Host.dll Acme.Controls.Widget.dll
  1. Client registers class with renamed host, via fusion or appx manifest:
    1. Fusion
    <file name="Acme.Controls.Widget.Host.dll">
        <activatableClass name="Acme.Controls.Widget" threadingModel="both" />
    </file>
    1. Appx
     <InProcessServer> 
         <Path>Acme.Controls.Widget.Host.dll</Path> 
         <ActivatableClass ActivatableClassId="Acme.Controls.Widget" ThreadingModel="both" /> 
     </InProcessServer>
  2. Client activates class: RoGetActivationFactory("Acme.Controls.Widget")
  3. Host finds target via Class Name or Host Name Probing (see above):
    1. "Acme.Controls.Widget.Host.Server.dll",
    2. "Acme.Controls.Widget.Server.dll",
    3. "Acme.Controls.Widget.dll"

Reg-Free Activation with Target Assembly Mapping

This example demonstrates how an activatableClass entry can be added to the host runtimeconfig.json to provide an explicit mapping from class ID to target assembly. This is useful when both the host dll and the target assembly have fixed names.

Class Host Target
"Acme.Controls.Widget" WinRT.Host.dll Widget.dll

This scenario follows a procedure similar to Reg-Free Activation with Generic Host above. In addition, the host dll's runtimeconfig.json contains an activatableClass section, similar to the following:

    {
      "runtimeOptions": { ... },
      "activatableClasses": {
        "Acme.Controls.Widget": "Widget.dll"
      }
    }

Manifest-Free Activation

This example demonstrates support for client code using manifest-free activation, which constrains the host name to match the class name.

Class Host Target
"Acme.Controls.Widget" Acme.Controls.Widget.dll Acme.Controls.Widget.Server.dll
  1. Client discovers host based on runtime class name: Acme.Controls.Widget.dll
  2. Client explicitly activates class:
    1. LoadLibrary("Acme.Controls.Widget.dll")
    2. GetProcAddress("DllGetActivationFactory")
    3. DllGetActivationFactory("Acme.Controls.Widget")
  3. Host finds target via Class Name or Host Name Probing (see above):
    1. "Acme.Controls.Widget.Server.dll"

Other Considerations

Non-Goals

The Host is neutral with respect to:

  • ThreadingModel
  • InProc/OOP In both cases, support is assumed to be provided by the component and/or activation logic

Performance

The examples above demonstrate that in typical cases, only a few probes are needed to find the target assembly. Even so, caching of probing results can be used to minimize steady-state overhead.

See also

Managed WinRT Activation of .NET Core components