Skip to content

Framework #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# .NET Core build folders
example/bin
example/obj
example/out
bin/
out/
obj/
.vs/

### Python ###
# Byte-compiled / optimized / DLL files
Expand Down
12 changes: 9 additions & 3 deletions clr_loader/ffi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

import cffi

from . import coreclr, hostfxr, mono
from . import coreclr, hostfxr, mono, framework

__all__ = ["ffi", "load_coreclr", "load_hostfxr", "load_mono"]
__all__ = ["ffi", "load_coreclr", "load_hostfxr", "load_mono", "load_framework"]

ffi = cffi.FFI()

for cdef in coreclr.cdef + hostfxr.cdef + mono.cdef:
for cdef in coreclr.cdef + hostfxr.cdef + mono.cdef + framework.cdef:
ffi.cdef(cdef)


Expand Down Expand Up @@ -40,6 +40,12 @@ def load_mono(path=None, gc=None):
return ffi.dlopen(path)


def load_framework():
path = "netframework_loader/bin/x64/Debug/net472/ClrLoader.dll"

return ffi.dlopen(path)


def _get_dll_name(name):
import sys

Expand Down
10 changes: 10 additions & 0 deletions clr_loader/ffi/framework.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cdef = [
"""
typedef void* pyclr_domain;
typedef int (*entry_point)(void* buffer, int size);

void* pyclr_create_appdomain(const char* name, const char* config_file);
entry_point pyclr_get_function(pyclr_domain domain, const char* assembly_path, const char* class_name, const char* function);
void pyclr_close_appdomain(pyclr_domain domain);
"""
]
29 changes: 29 additions & 0 deletions clr_loader/framework.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from .ffi import ffi, load_framework


_FW = None


class Framework:
def __init__(self, name=None, config_file=None):
global _FW
if _FW is None:
_FW = load_framework()

self._domain = _FW.pyclr_create_appdomain(
name or ffi.NULL, config_file or ffi.NULL
)

def get_callable(self, assembly_path, typename, function):
func = _FW.pyclr_get_function(
self._domain,
assembly_path.encode("utf8"),
typename.encode("utf8"),
function.encode("utf8"),
)

return func

def __del__(self):
if self._domain and _FW:
_FW.pyclr_close_appdomain(self._domain)
4 changes: 2 additions & 2 deletions example/example.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netcoreapp30;netstandard20</TargetFrameworks>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
</Project>
93 changes: 93 additions & 0 deletions netframework_loader/ClrLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;

namespace ClrLoader
{
public static class ClrLoader
{
delegate int EntryPoint(IntPtr buffer, int size);

[DllExport("pyclr_create_appdomain", CallingConvention.Cdecl)]
public static IntPtr CreateAppDomain(
[MarshalAs(UnmanagedType.LPUTF8Str)] string name,
[MarshalAs(UnmanagedType.LPUTF8Str)] string configFile
)
{
Print($"Creating AppDomain {name} with {configFile}");
if (!string.IsNullOrEmpty(name))
{
var setup = new AppDomainSetup
{
ConfigurationFile = configFile
};
var domain = AppDomain.CreateDomain(name, null, setup);

Print($"Located domain {domain}");

var handle = GCHandle.Alloc(domain, GCHandleType.Pinned);

Print($"Created handle {handle}");

return handle.AddrOfPinnedObject();
}
else
{
return IntPtr.Zero;
}
}

[DllExport("pyclr_get_function", CallingConvention.Cdecl)]
public static IntPtr GetFunction(
IntPtr domain,
[MarshalAs(UnmanagedType.LPUTF8Str)] string assemblyPath,
[MarshalAs(UnmanagedType.LPUTF8Str)] string typeName,
[MarshalAs(UnmanagedType.LPUTF8Str)] string function
)
{
try
{
var domainObj = AppDomain.CurrentDomain;
if (domain != IntPtr.Zero)
{
var handle = GCHandle.FromIntPtr(domain);
domainObj = (AppDomain)handle.Target;
}

var assembly = domainObj.Load(AssemblyName.GetAssemblyName(assemblyPath));
var type = assembly.GetType(typeName, throwOnError: true);
Print($"Loaded type {type}");
var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function);

return Marshal.GetFunctionPointerForDelegate(deleg);
}
catch (Exception exc)
{
Print($"Exception in {nameof(GetFunction)}: {exc.GetType().Name} {exc.Message}\n{exc.StackTrace}");
return IntPtr.Zero;
}
}

[DllExport("pyclr_close_appdomain", CallingConvention.Cdecl)]
public static void CloseAppDomain(IntPtr domain)
{
if (domain != IntPtr.Zero)
{
var handle = GCHandle.FromIntPtr(domain);
var domainObj = (AppDomain)handle.Target;
AppDomain.Unload(domainObj);
handle.Free();
}
}

static void Print(string s)
{
Console.WriteLine(s);
}
}

}
17 changes: 17 additions & 0 deletions netframework_loader/ClrLoader.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472</TargetFrameworks>
<Platforms>x64;x86</Platforms>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="UnmanagedExports.Repack.Upgrade" Version="1.2.1" />
</ItemGroup>

<PropertyGroup Condition=" '$(Platform)' == 'x86'">
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x64'">
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
</Project>