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.
Comments
Anonymous
December 05, 2009
Thanks for this code! I just ran into this error trying Z3 with F# and this did the trick!Anonymous
December 28, 2009
RuntimeEnvironment.GetRuntimeInterfaceAsObject is a .NET 4.0 only library. I'm getting a typeload exception on mixed-mode for 2.0 in a 3.5 targetted F# script. Unfortunately this fix doesn't work for that case. Any fix for that?Anonymous
March 06, 2010
Joel, I don't expect you should have the issue under .NET 3.5. Could you send a repro to fsbugs@microsoft.com?