Skip to content

Instantly share code, notes, and snippets.

@filmor
Last active December 30, 2022 18:34
Show Gist options
  • Save filmor/cf8a02aefff58be09a57ad2eca3cc246 to your computer and use it in GitHub Desktop.
Save filmor/cf8a02aefff58be09a57ad2eca3cc246 to your computer and use it in GitHub Desktop.
Initialize CLR via ctypes
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import subprocess\n",
"import re\n",
"from collections import namedtuple\n",
"import os"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"Runtime = namedtuple(\"Runtime\", \"name version path\")\n",
"\n",
"runtimes_l = subprocess.check_output(\"dotnet --list-runtimes\")\n",
"runtimes_l = runtimes_l.decode(\"utf8\").splitlines()\n",
"\n",
"runtimes = []\n",
"\n",
"for l in runtimes_l:\n",
" name, version, path = l.split(' ', 2)\n",
" runtimes.append(\n",
" Runtime(name=name, version=version, path=os.path.join(path[1:-1], version))\n",
" )\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Runtime(name='Microsoft.NETCore.App', version='2.2.3', path='C:\\\\Program Files\\\\dotnet\\\\shared\\\\Microsoft.NETCore.App\\\\2.2.3')\n"
]
}
],
"source": [
"rt = runtimes[-1]\n",
"print(rt)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import cffi\n",
"\n",
"ffi = cffi.FFI()\n",
"ffi.cdef(\"\"\"\n",
"__stdcall int coreclr_initialize(\n",
" const char* exePath,\n",
" const char* appDomainFriendlyName,\n",
" int propertyCount,\n",
" const char** propertyKeys,\n",
" const char** propertyValues,\n",
" void** hostHandle,\n",
" unsigned* domainId\n",
");\n",
"\n",
"__stdcall int coreclr_execute_assembly(\n",
" void* hostHandle,\n",
" unsigned int domainId,\n",
" int argc,\n",
" const char** argv,\n",
" const char* managedAssemblyPath,\n",
" unsigned int* exitCode\n",
");\n",
"\n",
"__stdcall int coreclr_create_delegate(\n",
" void* hostHandle,\n",
" unsigned int domainId,\n",
" const char* entryPointAssemblyName,\n",
" const char* entryPointTypeName,\n",
" const char* entryPointMethodName,\n",
" void** delegate\n",
");\n",
"\n",
"__stdcall int coreclr_shutdown(void* hostHandle, unsigned int domainId);\n",
"\"\"\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"import sys, glob\n",
"\n",
"coreclr = ffi.dlopen(os.path.join(rt.path, \"coreclr.dll\"))\n",
"\n",
"handle = ffi.new(\"void **\")\n",
"domain = ffi.new(\"unsigned *\")\n",
"\n",
"properties = {\n",
" \"APP_PATHS\": r\"c:\\git\\pythonnet\\bin\",\n",
" \"TRUSTED_PLATFORM_ASSEMBLIES\": \";\".join(glob.glob(rt.path + \"/*.dll\"))\n",
"}\n",
"\n",
"err_code = coreclr.coreclr_initialize(\n",
" sys.executable.encode(\"utf8\"),\n",
" b\"Python\",\n",
" len(properties),\n",
" list(ffi.new(\"char[]\", i.encode(\"utf8\")) for i in properties.keys()),\n",
" list(ffi.new(\"char[]\", i.encode(\"utf8\")) for i in properties.values()),\n",
" handle,\n",
" domain\n",
")\n",
"\n",
"if err_code != 0:\n",
" del handle\n",
" del domain\n",
" raise RuntimeError(err_code)\n",
"\n",
"handle = handle[0]\n",
"domain = domain[0]"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# coreclr.coreclr_shutdown(handle, domain)\n",
"# ffi.dlclose(coreclr)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<cdata 'void(*)()' 0x00007FFE2658304C>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"func_ptr = ffi.new(\"void**\")\n",
"\n",
"res = coreclr.coreclr_create_delegate(\n",
" handle,\n",
" domain,\n",
" b\"Python.Runtime\",\n",
" b\"Python.Runtime.PythonEngine\",\n",
" b\"InitExt\",\n",
" func_ptr\n",
")\n",
"\n",
"if res == 0:\n",
" func = ffi.cast(\"void* (*func)()\", func_ptr[0])\n",
"else:\n",
" import numpy as np\n",
" raise RuntimeError(f\"Error in create delegate: {hex(np.uint32(res))}\")\n",
"\n",
"func"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"14412"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import os\n",
"os.getpid()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"func()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment