Setting Host Policy in appdomain

Due to popular demand, I am posting an example how to set host policy in appdomain.

(If you don't know what host policy is, please refer to the following two blogs:

Aspnet.Config
https://blogs.msdn.com/junfeng/archive/2004/10/07/239317.aspx

Assembly Binding Policy
https://blogs.gotdotnet.com/alanshi/commentview.aspx/d4edb084-c625-4b6e-8e5c-7c2580cfcee9)

The only way to set host policy is through CLR hosting API.

There are four CLR hosting APIs defined in mscoree.idl in .Net framework SDK.

#pragma midl_echo("STDAPI CorBindToRuntimeHost(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, LPCWSTR pwszHostConfigFile, VOID* pReserved, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);")
#pragma midl_echo("STDAPI CorBindToRuntimeEx(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);")
#pragma midl_echo("STDAPI CorBindToRuntimeByCfg(IStream* pCfgStream, DWORD reserved, DWORD startupFlags, REFCLSID rclsid,REFIID riid, LPVOID FAR* ppv);")
#pragma midl_echo("STDAPI CorBindToRuntime(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);")

The only one can set host policy is CorBindToRuntimeHost. The host policy is set automatically in every appdomain.

Documentation for CLR hosting interface can be found at https://www.gotdotnet.com/team/clr/HostingInterfaces.aspx.

The example below hosts CLR, then executes a managed application in default appdomain. The managed application simply loads an assembly to demostrate that host policy is applied.

E:\demo>more hostdemo.cpp
#include "windows.h"
#include "stdio.h"
#include "mscoree.h"

#import <mscorlib.tlb> raw_interfaces_only high_property_prefixes("_get","_put","_putref")

using namespace mscorlib;

int wmain(int argc, WCHAR **argv)
{
if (argc != 3) {
printf("Usage: HostDemo HostConfigFile AppToExecute\n");
return 1;
}

    ICorRuntimeHost *pHost = NULL;
IUnknown *pAppDomainThunk = NULL;
_AppDomain *pAppDomain = NULL;

    // let's host CLR
HRESULT hr = CorBindToRuntimeHost( L"v1.1.4322", // pwzVersion
L"wks", // pwzBuildFlavor
argv[1], // host config file
NULL, // reversed
0, // startup flag,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(VOID**)&pHost);

    if (FAILED(hr)) {
printf("CorBindToRuntimeHost failed with hr=0x%x.\n", hr);
return 2;
}

    // Start the runtime
hr = pHost->Start();
if (FAILED(hr)) {
printf("ICorRuntimeHost->Start failed with hr=0x%x.\n", hr);
return 3;
}

    // Get the default appdomain.
hr = pHost->GetDefaultDomain(&pAppDomainThunk);
if (FAILED(hr)) {
printf("ICorRuntimeHost->GetDefaultDomain failed with hr=0x%x.\n", hr);
return 4;
}

    // Get System::_AppDomain interface
hr = pAppDomainThunk->QueryInterface(__uuidof(_AppDomain),
(void**) &pAppDomain);
if (FAILED(hr)) {
printf("Can't get System::_AppDomain interface\n");
return 5;
}

    long lRet= 0;
// call System::_AppDomain::ExecuteAssembly(String)
hr = pAppDomain->ExecuteAssembly_2(_bstr_t(argv[2]), &lRet);
if (FAILED(hr)) {
printf("_AppDomain::ExecuteAssembly_2 failed with hr=0x%x.\n", hr);
return 6;
}

    return 0;
}

E:\demo>more hello.cs
using System;
using System.Reflection;

public class test
{
public static void Main()
{
Console.WriteLine(Assembly.Load("test, version=1.0.0.0, culture=neutral, publickeytoken=ba6def5dd8a8ddac").Location);
}
}

E:\demo>more test.cs
using System;
using System.Reflection;

[assembly:AssemblyKeyFile("1.snk")]
public class test
{
public String WhoAmI()
{
return "Test.dll";
}
}

E:\demo>more build.bat
cl hostdemo.cpp mscoree.lib
csc hello.cs
csc /t:library test.cs
move test.dll c:\temp\test.dll

E:\demo>more example.config
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="test"
publicKeyToken="ba6def5dd8a8ddac"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="0.0.0.0"/>
<codeBase version="0.0.0.0" href="c:\temp\test.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

E:\demo>build.bat

E:\demo>cl hostdemo.cpp mscoree.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

hostdemo.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.

/out:hostdemo.exe
hostdemo.obj
mscoree.lib

E:\demo>csc hello.cs
Microsoft (R) Visual C# .NET Compiler version 7.10.6001.4
for Microsoft (R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.
E:\demo>csc /t:library test.cs
Microsoft (R) Visual C# .NET Compiler version 7.10.6001.4
for Microsoft (R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.

E:\demo>move test.dll c:\temp\test.dll
1 file(s) moved.

E:\demo>hostdemo example.config hello.exe
c:\temp\test.dll

Due to the restriction of codebase in host policy, I have to use a bogus redirect in example.config to make sure the codebase is picked up correctly.

The example is compiled with VS.Net 2003, and run under .Net framework 1.1.