F# Scripting, .NET 4.0 and Mixed-mode assemblies

Jomo Fisher—There is a nice F# and DirectX demo that has been floating around for a while now. A recent version can be found here: https://code.msdn.microsoft.com/fsharpsamples/Wiki/View.aspx?title=Home&version=2

One of the recent problems we’ve seen is that, because of the support for side-by-side runtimes, .NET 4.0 has changed the way that it binds to older mixed-mode assemblies. These assemblies are, for example, those that are compiled from C++\CLI. Currently available DirectX assemblies are mixed mode. If you see a message like this then you know you have run into the issue:

Mixed mode assembly is built against version 'v1.1.4322' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.

Though you may see it in the F# interactive, this message originates as an exception in the .NET 4.0 runtime. You may also see the message if you recompile a C#, VB or F# application that uses DirectX or other mixed-mode assembly against the .NET 4.0 runtime.

The good news for applications is that you have the option of falling back to .NET 2.0 era binding for these assemblies by setting an app.config flag like so:

  <startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>

Things get a little trickier for scripts, though, since there is no .exe running. Here is a little snippet of code you can run in the F# repl to switch to 2.0 binding mode:

open System

open System.Runtime.InteropServices

open System.Runtime.CompilerServices

[<ComImport>]

[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>]

[<Guid("BD39D1D2-BA2F-486A-89B0-B4B0CB466891")>]

type ICLRRuntimeInfo =

    // vtable slots

    abstract xGetVersionString : unit -> unit

    abstract xGetRuntimeDirectory : unit -> unit

    abstract xIsLoaded : unit -> unit

    abstract xIsLoadable : unit -> unit

    abstract xLoadErrorString : unit -> unit

    abstract xLoadLibrary : unit -> unit

    abstract xGetProcAddress : unit -> unit

    abstract xGetInterface : unit -> unit

    abstract xSetDefaultStartupFlags : unit -> unit

    abstract xGetDefaultStartupFlags : unit -> unit

    [<MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)>]

    abstract BindAsLegacyV2Runtime : unit -> unit

let rtInfo = RuntimeEnvironment.GetRuntimeInterfaceAsObject(Guid.Empty,typeof<ICLRRuntimeInfo>.GUID) :?> ICLRRuntimeInfo

rtInfo.BindAsLegacyV2Runtime()

This needs to be the first thing that runs in your interactive window.

 

This posting is provided "AS IS" with no warranties, and confers no rights.