.NET 4 and Mixed Mode Assembly loading menu

User Tag List

Results 1 to 10 of 10
  1. #1
    adaephon's Avatar Active Member
    Reputation
    76
    Join Date
    May 2009
    Posts
    167
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    .NET 4 and Mixed Mode Assembly loading

    I decided to upgrade my project to use .NET 4.0 to try out some of the newer features. Initially I ran into some problems with my CLR Host, due to changes in the hosting architecture with .NET 4 (The new CLR can load multiple runtimes into a single process, and the interfaces for hosting have changed).

    Anyway, I got that working based on link posted by TOM_RUS in this thread http://www.mmowned.com/forums/wow-me...-question.html (yes I know, things aren't moving quickly in this camp - I keep getting distracted by other projects).

    Once I made the change to .NET 4, I was no longer able to use the XNA library as it was compiled for v2 of the CLR. At the time I ran into this problem, I didn't really look into it and just rolled my own Vector3 struct.

    However, I dug a bit deeper today to find out what was actually behind it. v4 of the CLR can run .NET 2 assemblies, but unlike previous versions, this isn't its default behaviour. You might've come across examples that advise to add this to the application's configuration file:
    Code:
    <startup useLegacyV2RuntimeActivationPolicy="true">
      <supportedRuntime version="v4.0"/>
    </startup>
    Given that I'm injecting a CLR loader into another process and loading assemblies from there, I'm assuming the configuration wouldn't be loaded properly (once again, haven't looked into this, but I assume it would look for the application's config, i.e. WoW.exe.config). Either way, I assumed the config would just be corresponding to some function call in the hosting APIs, and Googling around found this: Sharp Things : F# Scripting, .NET 4.0 and Mixed-mode assemblies.

    Basically, you can use the ICLRRuntimeInfo::BindAsLegacyV2Runtime() to bind an executing runtime to handle legacy V2 CLR assemblies (Reference: ICLRRuntimeInfo::BindAsLegacyV2Runtime Method).

    With this information, a simple modification to my CLR loader allows me to load .NET 4 assemblies that reference .NET 3.5/2.0 (CLR 2) assemblies, and I can once again use XNA.

    Some relevant code (ignore lack of error handling):
    Code:
    	ICLRRuntimeInfo* lpRuntimeInfo = NULL;
    	lpMetaHost->GetRuntime(
    		L"v4.0.30128",
    		IID_ICLRRuntimeInfo,
    		(LPVOID*)&lpRuntimeInfo);
    
    	lpRuntimeInfo->GetInterface(
    		CLSID_CLRRuntimeHost,
    		IID_ICLRRuntimeHost,
    		(LPVOID*)&m_pClrRuntimeHost);
    
    	m_pClrRuntimeHost->Start(); // ICLRRuntimeHost
    
    	lpRuntimeInfo->BindAsLegacyV2Runtime();
    Thought this information might be interesting / useful to some of the members here who are also injecting .NET CLR runtimes into WoW. Also, the extra digging was prompted by finding out that XNA 4.0 CTP has been released, and subsequently finding out that despite its VS2010 integration and other new features, its still a v2 runtime assembly. XNA Creators Club Online - downloads

    Hopefully this is useful to someone . Enjoy

    .NET 4 and Mixed Mode Assembly loading
  2. #2
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Heh, I spent a good 30-40 min or so scratching my head about this one as well.

    That one line to bind for the 2.0 runtime was the key.

    Also, 4.0 is WELL worth the upgrade.

  3. #3
    caytchen's Avatar Contributor
    Reputation
    138
    Join Date
    Apr 2007
    Posts
    162
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey,

    Trying to migrate over to 4.0, and I can't seem to start the CLR. Everything works fine until I call Start on the ICLRRuntimeHost, from which point on it just won't return. Now I understand it may take some time to load the runtime, but definitely not 10 minutes+. Also, there is a HOST_E_TIMEOUT return value for Start; not getting that either.
    Documentation suggests it might not even be necessary to call Start, since it will be done implicitly once I start executing managed code. So I got rid of the Start call, and jump directly to ExecuteInDefaultAppDomain. That, however, only returns HOST_E_CLRNOTAVAILABLE (pointing me back to Start..). Runtime version is the same, v4.0.30128, e.g. .NET 4.0 RC.

    Anyone experienced something similar?

  4. #4
    adaephon's Avatar Active Member
    Reputation
    76
    Join Date
    May 2009
    Posts
    167
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Haven't experienced anything similar and starting runtime host is pretty much instant. If you've just taken a CLR 2.0 runtime host and changed the version string to v4.0.30128, then I'd hazard a guess that that could be the problem. .NET 4 introduces the capability to host multiple CLRs in one process and due to that all the hosting interfaces have changed. Check out MSDN docs for ICLRMetaHost (ICLRMetaHost Interface).

  5. #5
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    // This is the actual host object we need to keep in memory.
    ICLRRuntimeHost* pClrHost                 = NULL;
    
    unsigned __stdcall ThreadMain( LPVOID pParam )
    {
        // Get the policy object, so we can determine which runtime to use.
        ICLRMetaHostPolicy* pMetaHostPolicy     = NULL;
        HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy);
    
        if (FAILED(hr))
        {
            MessageBox(NULL, L"Could not create a ICLRMetaHostPolicy object!", L"Injection - Error", MB_OK);
            return 1;
        }
        
        ICLRRuntimeInfo* pRuntimeInfo = NULL;
        // Get the runtime info object. Allow the assembly to tell US what runtime to use.
        DWORD pcchVersion = 0;
        DWORD dwConfigFlags = 0;
        hr = pMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, 
                                                    dllLocation.c_str(), NULL,
                                                    NULL, &pcchVersion,
                                                    NULL, NULL, &dwConfigFlags,
                                                    IID_ICLRRuntimeInfo,
                                                    (LPVOID*)&pRuntimeInfo);
    
        if (FAILED(hr))
        {
            MessageBox(NULL, L"Could not create an ICLRRuntimeInfo object.", L"Injection - Error", MB_OK);
            return 1;
        }
    
        // Allow the runtime to load .NET 2.0 mixed-mode libraries. (This covers 2.0-3.5 SP1)
        hr = pRuntimeInfo->BindAsLegacyV2Runtime();
    
        if (FAILED(hr))
        {
            MessageBox(NULL, L"Could not bind as legacy v2 runtime.", L"Injection - Error", MB_OK);
            return 1;
        }
        
        hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pClrHost);
        
        if (FAILED(hr))
        {
            MessageBox(NULL, L"Could not get an instance of ICLRRuntimeHost!", L"Injection - Error", MB_OK);
            return 1;
        }
    
        hr = pClrHost->Start();
        
        if (FAILED(hr))
        {
            MessageBox(NULL, L"Failed to start the CLR!", L"Injection - Error", MB_OK);
            return 1;
        }
    
        DWORD dwRet = 0;
        // Execute the Main func in the domain manager, this will block indefinitely.
        // (Hence why we're in our own thread!)
        hr = pClrHost->ExecuteInDefaultAppDomain(dllLocation.c_str(), NAMESPACE_AND_CLASS, MAIN_METHOD, MAIN_METHOD_ARGS, &dwRet);
            
        if (FAILED(hr))
        {
            MessageBox(NULL, L"Failed to execute in the default app domain!", L"Injection - Error", MB_OK);
            return 1;
        }
    
        return 0;
    }
    Edit: Note to self: when cutting out old code, make sure to leave the REQUIRED STUFF IN THERE
    Last edited by Apoc; 04-09-2010 at 08:02 PM.

  6. #6
    caytchen's Avatar Contributor
    Reputation
    138
    Join Date
    Apr 2007
    Posts
    162
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by adaephon View Post
    Haven't experienced anything similar and starting runtime host is pretty much instant. If you've just taken a CLR 2.0 runtime host and changed the version string to v4.0.30128, then I'd hazard a guess that that could be the problem. .NET 4 introduces the capability to host multiple CLRs in one process and due to that all the hosting interfaces have changed. Check out MSDN docs for ICLRMetaHost (ICLRMetaHost Interface).
    I'm using the new APIs. Pasted my code here: Private Paste - Pastie

    @Apoc: I've added the code to get pClrHost. Still getting HOST_E_CRLNOTAVAILABLE at the execute though.

    [UPDATE]
    Saw you edited your post, and I've tried running it again. Still freezing at Start :/
    Regarding the HostControl in my paste: documentation says it's required (for some corner cases), so I put in a default HostControl. Behaves the same without it though, so it shouldn't matter.
    [/UPDATE]
    Last edited by caytchen; 04-09-2010 at 08:25 PM.

  7. #7
    caytchen's Avatar Contributor
    Reputation
    138
    Join Date
    Apr 2007
    Posts
    162
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, solved it. Working great now, thanks for the help
    As to what caused it, I really have no idea. I did a fresh install of VS2010 RC and the .NET Framework, and it works now. I blame the release candidate, seriously that thing is ****ed up. Managed to corrupt one project of mine to the point where it says "The Visual C++ project ... is targeting ".NETFramework,Version=v4.0". Can't wait for the real thing on monday.

  8. #8
    !@^^@!'s Avatar Active Member
    Reputation
    23
    Join Date
    Feb 2007
    Posts
    155
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hey im using Easyhook for my injection because i have absolutly no clue about c++ but i'd still like to use .net 4 in my app, so i've tracked down the methode in the source code that starts up the CLR in easyhook and it looks like this:

    Code:
    EASYHOOK_NT_INTERNAL CompleteManagedInjection(LPREMOTE_INFO InInfo)
    {
    /*
    Description:
    
        Loads the NET runtime into the calling process and invokes the
        managed injection entry point.
    */
        
        ICLRRuntimeHost*        ClrHost = NULL;
        DWORD                    ErrorCode = 0;
        WCHAR                   ParamString[MAX_PATH];
        REMOTE_ENTRY_INFO       EntryInfo;
        HMODULE                 hMsCorEE = LoadLibraryA("mscoree.dll");
        PROC_CorBindToRuntime*  CorBindToRuntime = (PROC_CorBindToRuntime*)GetProcAddress(hMsCorEE, "CorBindToRuntime");
        DWORD                   RetVal;
    
        if(CorBindToRuntime == NULL)
            UNMANAGED_ERROR(10);
    
        // invoke user defined entry point
        EntryInfo.HostPID = InInfo->HostProcess;
        EntryInfo.UserData = InInfo->UserData;
        EntryInfo.UserDataSize = InInfo->UserDataSize;
    
        // load NET-Runtime and execute user defined method
        if(!RTL_SUCCESS(CorBindToRuntime(NULL, NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**)&ClrHost)))
            UNMANAGED_ERROR(11);
    
        ClrHost->Start();
    
        /*
            Test library code.
            This is because if once we have set the remote signal, there is no way to
            notify the host about errors. If the following call succeeds, then it will
            also do so some lines later... If not, then we are still able to report an error.
    
            The EasyHook managed injection loader will establish a connection to the
            host, so that further error reporting is still possible after we set the event!
        */
        RtlLongLongToUnicodeHex((LONGLONG)&EntryInfo, ParamString);
    
        if(!RTL_SUCCESS(ClrHost->ExecuteInDefaultAppDomain(
                InInfo->UserLibrary, 
                L"EasyHook.InjectionLoader", 
                L"Main", 
                ParamString, 
                &RetVal)))
            UNMANAGED_ERROR(12);
    
        if(!RetVal)
            UNMANAGED_ERROR(13);
    
        // set and close event
        if(!SetEvent(InInfo->hRemoteSignal))
            UNMANAGED_ERROR(22);
    
        CloseHandle(InInfo->hRemoteSignal);
    
        InInfo->hRemoteSignal = NULL;
    
        // execute library code (no way for error reporting, so we dont need to check)
        ClrHost->ExecuteInDefaultAppDomain(
            InInfo->UserLibrary, 
            L"EasyHook.InjectionLoader", 
            L"Main", 
            ParamString, 
            &RetVal);
    
    ABORT_ERROR:
    
        // release resources
        if(ClrHost != NULL)
            ClrHost->Release();
    
        if(hMsCorEE != NULL)
            FreeLibrary(hMsCorEE);
    
        return ErrorCode;
    }
    Now to the question: what do i need to replace with what either apoc or adaephon posted and still keep the error checking and what not? because I can see the similarites and what the code does but i don't know how so i don't really know how to merge all the information into a solution

    If that's too much to ask, any hints/points in what direction i should be heading?

    Thanks in advance.

  9. #9
    caytchen's Avatar Contributor
    Reputation
    138
    Join Date
    Apr 2007
    Posts
    162
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The snippet you posted uses deprecated APIs, most notably CorBindToRuntime. You can use what Apoc posted, it basically has everythig you need in it. Including error handling

  10. #10
    !@^^@!'s Avatar Active Member
    Reputation
    23
    Join Date
    Feb 2007
    Posts
    155
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah i know that, what im looking for is integrating his error handling with what's already there so i don't **** up the easyhook dll

Similar Threads

  1. Replies: 5
    Last Post: 12-28-2009, 01:16 PM
  2. visual c++ 08 instal without .net frame and sp1?
    By pokemonz in forum WoW EMU Questions & Requests
    Replies: 0
    Last Post: 06-16-2009, 01:43 AM
  3. Another question about the Battle.net scam and retriving possibilitys
    By Paradiise in forum World of Warcraft General
    Replies: 4
    Last Post: 06-01-2009, 08:27 AM
  4. UnMerging Battle.net acct and wow account
    By Kyiz in forum World of Warcraft General
    Replies: 4
    Last Post: 04-10-2009, 04:29 PM
  5. [How-To] Skip to Battlenet and Windowed Mode
    By Insanus in forum Diablo 2
    Replies: 3
    Last Post: 08-28-2008, 12:07 PM
All times are GMT -5. The time now is 02:01 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search