locked
Problem using ‘useLegacyV2RuntimeActivationPolicy’ & supportedRuntime in an application

    Question

  • Hello,

    I hope I have the correct forum for this question.

    I've modified a couple of different applications' .config file like this:

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

    When I did this for devenv.exe.config (VS 2005 - don't ask :) ), things work great - most of the time Visual Studio used .NET 2.0 but I was able to make use of an assembly targeting .NET 4.0 framework.

    I tried to do the same thing for a custom .exe, which happens to be based on MS CAB (slightly modified) and has a hybrid mix of WPF and WinForms content. As soon as I modified this application's app config file, I started getting this exception, sometime during application startup:

    The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone). System.InvalidOperationException: The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone).

    There's a big long stack trace that doesn't show anything in my application code directly (just a bunch of MS assemblies).

    If I modify the application's .config file to this:

    <startup useLegacyV2RuntimeActivationPolicy="true">
    </startup>

    i.e.I remove the supportedRuntime element, then the application doesn't throw this exception. But when I go to the point in my code where I try to load my .NET 4 assembly, if fails with this:

    System.BadImageFormatException: Could not load file or assembly '' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.

    I guess this is expected.

    I have two questions:

    1) Any idea why I'm getting the System.InvalidOperationException exception when I modify this application's configuration file to include the supportedRuntime element, adding .NET 4 support and any suggestions on what I can do about it?

    2) If the answer is "no idea why/don't know what you can do about it", then is possible for my .NET 3.5 SP1 code (C#) to provide more fine grain support for conditionally adding .NET 4 runtime support for a certain assembly(ies) without converting my entire application to target .NET 4, or without using the declarative config file approach? At some point I would convert the entire application to target .NET 4, but for the short term this is daunting task and I'm hope for some short term solution/hack.

    Thank you very much for any advice you can give!

    Friday, March 26, 2010 4:14 PM

Answers

All replies

  • Re 1) No idea. It depends on the application and which APIs it uses. There were breaking changes in .NET 4 and this application is likely hitting one. You have to debug it to find out more details.

    Re 2) You can use COM objects from 3.5 which will be implemented in 4.0 and vice versa. However you cannot interact between 3.5 and 4.0 without the COM layer in between. They (3.5 and 4.0) don't know about each other. Check out more about in-proc SxS:
        http://blogs.msdn.com/clrteam/archive/2009/06/03/in-process-side-by-side-part1.aspx
        http://blogs.msdn.com/clrteam/archive/2009/06/07/in-process-side-by-side-part-2-common-in-proc-sxs-scenarios.aspx
        http://msdn.microsoft.com/en-us/magazine/ee819091.aspx
        http://channel9.msdn.com/shows/Going+Deep/CLR-4-Side-by-Side-In-Process-What-How-Why/

    -Karel

    • Marked as answer by Notre Wednesday, March 31, 2010 4:13 PM
    Friday, March 26, 2010 5:05 PM
  • Thank you Karel for your comments!  I'll review the various links you provided. I had another idea, that may equally not work, but I'd like to run it past you just in case.

    I got the idea of creating a separate app domain. To test it, I created a WinForm project targeting .NET 2. I then created a class library targeting .NET 4. In my WinForm project, I added the following code:

            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = "path to .NET 4 assembly";
            setup.ConfigurationFile = System.Environment.CurrentDirectory +
              "\\DotNet4AppDomain.exe.config";

            // Set up the Evidence
            Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
            Evidence evidence = new Evidence(baseEvidence);

            // Create the AppDomain     
            AppDomain dotNet4AppDomain = AppDomain.CreateDomain("DotNet4AppDomain", evidence, setup);
            try
            {
                Assembly doNet4Assembly = dotNet4AppDomain.Load(
                   new AssemblyName("MyDotNet4Assembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=66f0dac1b575e793"));
                MessageBox.Show(doNet4Assembly.FullName);
            }
            finally
            {
                AppDomain.Unload(dotNet4AppDomain);
            }
    My DotNet4AppDomain.exe.config file looks like this:

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

    Unfortunately, this throws the BadImageFormatException when dotNet4AppDomain.Load is executed

     

    Thank you for any further comments you can give.

    Friday, March 26, 2010 6:10 PM
  • Hi Karel,

    After reviewing the links you provided, and based in particular on a comment Rick Byers made in the channel 9 video about thinking of CLR SxS as being between the AppDomain and process boundaries, I think the AppDomain idea I have above likely won't work either. (Although if you can confirm that either way, that would be great).

    You mentioned that if I have a COM layer, then it should work.  So, going back to my sample application above, I marked my .NET 4 assembly's class as ComVisible, did the RegAsm thing to register my component with the registry, and then installed the assemby into the GAC.  Now, how can I:

    1) Call this .NET 4 assembly's class as if it were a COM object from my .NET 2 runtime client application?  I tried finding my .NET 4 assembly in the COM Add Reference tab of my .NET 2 class' project, but it doesn't show up.  I used OLE/View, and also couldn't find my .NET 4 component's type library entry.  Finally, I re-ran regasm with the regfile switch so I can see what is to being dumped into the registry.  In the output reg file, I don't see any entries for HKEY_CLASSES_ROOT\TypeLib.

    2) Assuming I could somehow reference and call my .NET based COM component from my .NET 2 based application, how would I specify that the COM component should load the .NET 4 runtime?  Or would it magically figure it out somehow, since I compiled the .NET based COM component to target the .NET 4 runtime?

    Thanks,

    Notre

    Friday, March 26, 2010 9:38 PM
  • I figured out why entries were not being added to HKEY_CLASSES_ROOT\TypeLib; I failed to include the "tlb" switch with regasm.  Now, it shows up in OLE/View and I can see it in VS' COM reference tab.  However, when I select COM object in VS's COM reference dialog tab, it says:

    A reference to '<myAssemblyName>' could not be added.

    The ActiveX type library '<path to type library file>' was exported from a .NET assembly and cannot be added as a reference.

    Add a reference to the .NET assembly instead.

    I think this behaviour is as designed.  However, referencing the .NET assembly isn't going to work for me because of the multiple runtime versions involved.

    So, I'm back to my original problem, where I can't directly reference or use reflection (even in a separate ApDomain) to an assembly in a different runtime.  And I tried to fake having a COM layer in between as just described, but I can't get that working either.  Please advise.

    Thanks,

    Notre

    Friday, March 26, 2010 9:59 PM
  • 2.0 runtime cannot load 4.0 assemblies, that's why your AppDomain trick doesn't work. 2.0 runtime also cannot reflect over 4.0 assemblies as it is newer format potentiallly breaking.
    Check out this link: http://www.vistadb.net/blog/post/2009/12/03/How-Dot-Net-4-Side-by-Side-will-impact-API-writers.aspx

    The Visual Studio error you got means, that you will have to do some extra manual steps: Manually create a COM import class in your main app for your COM export in your addin/library.
    I will try to test it out on my VM once it is set up.

    -Karel

    Saturday, March 27, 2010 2:01 AM
  • Thank you Karel.  That makes sense re: app domains and .NET 2 runtime not being able to load 4.0 assemblies.

     

    I eagerly look forward to the results of your testing.  Assuming that what you suggest works, I would appreciate any guidance (e.g. web links) on 'manually creating a COM import class in your main app for your COM export in your addin/library', because I don't know how do do this.

     

    Thanks,

    Notre

    • Edited by Notre Saturday, March 27, 2010 7:14 PM request help with COM import class
    Saturday, March 27, 2010 7:01 PM
  • Hi Karel,

    I've created my own ATL based COM object, which I would use as the go between the .NET 2 runtime assembly and .NET 4 runtime assembly. I tried to export my C# based .NET 4 class to COM.  I can get the ATL based COM component to compile and sort of reference the C# project, and I can see the type library but all the list of methods appears empty :( (Well, not completely empty - I get the standard IUnknown and IDispatch methods, but none of my application specific methods). 

    When I look at the generated .tlh file, I can see entries for coclasses, interfaces, smart pointers, etc.  But when I look at any of the interfaces in the .tlh file, they appear to be empty.  For example:

    struct __declspec(uuid("b1cadeba-c5f2-3faa-a8c4-ed60802098e9"))
    _Comment : IDispatch
    {};

    Even though in my C# code, I had explicitly implemented an interface on the class, made the whole assembly ComVisible, assigned guids to the class and interfaces.  All the methods in the class' (implicit) implementation of the interface are public.

    I've been trying to follow this tutorial: http://msdn.microsoft.com/en-us/library/aa645738(VS.71).aspx 

    (and http://www.csharphelp.com/2006/08/building-com-objects-in-c/ and http://www.murrayc.com/learning/windows/usecomfromatl.shtml).

    I'm not sure if the problem (not seeing methods) is related to importing mscorlib.tlb or something else I'm doing wrong.  I remember from one of the videos that the .NET 4 runtime is separate from the .NET 2 runtime, even in separate DLLs.  So, this might not be the right type library to import to make use of .NET 4 functionality...

    Notre

    • Edited by Notre Tuesday, March 30, 2010 1:56 AM provide info on .tlh file
    Tuesday, March 30, 2010 1:05 AM
  • Good news - I got this working.  I went with the ATL based COM object, as described above.  I was able to resolve the problem of the 'empty' list of methods (other than IDispatch and IUnkown).  The problem was that my .NET 4 code's interface was not made public (even though the class was public) and also I missed the Guid in the AssemblyInfo.cs file.  After correctly these two problems, I was able to properly reference the .NET based COM object in my ATL code, and my .NET 2 runtime client was able to make use of the .NET 4 runtime code, by using the ATL COM object as a go between.

    Thanks for your help, Karel!

    Notre

    Wednesday, March 31, 2010 4:13 PM