代码示例
C#端代码
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using System.Runtime.CompilerServices;
using WinFormsTest;
[StructLayout(LayoutKind.Sequential)]
public struct Vec3
{
public float x;
public float y;
public float z;
}
namespace WinFormsTest
{
public unsafe static class Program
{
//1. 函数指针
public static delegate* unmanaged<void> func_ptr;
//如果使用2.委托
public static IntPtr funcIntPtr;
private delegate void CpptestDelegate();
private static CpptestDelegate _cpptestDelegate;
[STAThread]
public static void Main()
{
cpptest();
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
[UnmanagedCallersOnly]
public static void Test1()
{
Console.WriteLine($"TestTestTest!");
}
[UnmanagedCallersOnly]
public static void Test2(Vec3 vec)
{
Console.WriteLine($"vec3({vec.x.ToString()}, {vec.y.ToString()} , {vec.z.ToString()})");
}
[UnmanagedCallersOnly]
public static void SetFuncPtr(IntPtr ptr)
{
//1.函数指针
func_ptr = (delegate* unmanaged<void>)ptr;
//2.委托方式
funcIntPtr = ptr;
_cpptestDelegate = Marshal.GetDelegateForFunctionPointer<CpptestDelegate>(ptr);
}
public static void cpptest()
{
// 1.直接使用函数指针调用非托管函数
func_ptr();
//// 2.委托
//_cpptestDelegate?.Invoke();
}
}
}
C++端代码
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//标准头文件
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
// nethost
#include <nethost.h>
// "Host Framework Resolver"
#include <hostfxr.h> //
#include <coreclr_delegates.h>
// Windows
#include <Windows.h>
using string_t = std::basic_string<char_t>;
struct Vec3
{
public:
float x;
float y;
float z;
};
//使用匿名namespace,可以避免不同文件中的同名符号(变量、函数等)之间发生冲突。由于匿名namespace中的符号只在声明它们的文件内可见,因此不会与其他文件中的符号冲突。
namespace
{
//保存 hostfxr exports 的全局变量
hostfxr_initialize_for_dotnet_command_line_fn init_for_cmd_line_fptr;
hostfxr_initialize_for_runtime_config_fn init_for_config_fptr;
hostfxr_get_runtime_delegate_fn get_delegate_fptr;
hostfxr_run_app_fn run_app_fptr;
hostfxr_close_fn close_fptr;
// 函数:获取函数指针
get_function_pointer_fn get_function_pointer;
//ZQJ:其他全局变量
//const char_t* dotnet_root = L"F:\\Legacy\\MyProjects\\CPPdotnet8Test\\Debug\\dotnet8min";
const char_t* dotnet_root = L"C:\\Program Files\\dotnet"; // DOTNET安装地址
const char_t* app_name = L"WinFormsTest.dll";
//const char_t* app_name = L"App.dll";// L"App.dll";//应用程序文件名
// 前向声明
bool load_hostfxr(const char_t* app);
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* assembly);
int run_app_example(const string_t& root_path);
void rew_bind_csharp_function(const char_t* type_name, const char_t* method_name, void** delegate);
template<typename T>
T rew_get_csharp_function(const char_t* type_name, const char_t* method_name);
}
//Main函数
int __cdecl wmain(int argc, wchar_t* argv[])
{
//获取当前可执行程序的目录
// (假设要加载的托管程序集及其运行时配置文件位于host旁边)
char_t host_path[MAX_PATH];
auto size = ::GetFullPathNameW(argv[0], sizeof(host_path) / sizeof(char_t), host_path, nullptr);
assert(size != 0);
string_t root_path = host_path;
auto pos = root_path.find_last_of(L'\\');
assert(pos != string_t::npos);
root_path = root_path.substr(0, pos + 1);
//运行示例应用程序
return run_app_example(root_path);
}
extern "C" void cpptest()
{
std::cout << "CPP:Hello!" << std::endl;
}
namespace
{
//运行示例应用程序
int run_app_example(const string_t& root_path)
{
const string_t app_path = root_path + app_name;
//加载hostfxr
if (!load_hostfxr(app_path.c_str()))
{
std::wcout << "失败load_hostfxr" << std::endl;
assert(false && "Failure: load_hostfxr()");
return EXIT_FAILURE;
}
// 加载.Net Core
hostfxr_handle cxt = nullptr;
std::vector<const char_t*> args{ app_path.c_str(), L"app_arg_1", L"app_arg_2" };
int rc = init_for_cmd_line_fptr(args.size(), args.data(), nullptr, &cxt);
if (rc != 0 || cxt == nullptr)
{
std::wcout << "失败init_for_cmd_line_fptr" << std::endl;
std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return EXIT_FAILURE;
}
// 获取函数指针
rc = get_delegate_fptr( cxt, hdt_get_function_pointer, (void**)&get_function_pointer);
if (rc != 0 || get_function_pointer == nullptr)
std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;
//控制台程序"App.dll"测试(已弃用)
{
//// App.IsWaiting的函数指针
//typedef unsigned char (CORECLR_DELEGATE_CALLTYPE* is_waiting_fn)();
//is_waiting_fn is_waiting;
//rc = get_function_pointer(
// L"App, App",
// L"IsWaiting",
// UNMANAGEDCALLERSONLY_METHOD,
// nullptr, nullptr, (void**)&is_waiting);
//assert(rc == 0 && is_waiting != nullptr && "Failure: get_function_pointer()");
//// App.Hello的函数指针
//typedef void (CORECLR_DELEGATE_CALLTYPE* hello_fn)(const char*);
//hello_fn hello;
//rc = get_function_pointer(
// L"App, App",
// L"Hello",
// UNMANAGEDCALLERSONLY_METHOD,
// nullptr, nullptr, (void**)&hello);
//assert(rc == 0 && hello != nullptr && "Failure: get_function_pointer()");
//// 在主程序调用不同线程的函数
//std::thread t([&]
// {
// while (is_waiting() != 1)
// std::this_thread::sleep_for(std::chrono::milliseconds(100));
// for (int i = 0; i < 3; ++i)
// hello("from host!");
// });
//// 运行App
//run_app_fptr(cxt);
//t.join();
}
//窗体"WinformTest"测试
{
// .Test1的函数指针(方式1)
auto test1 = rew_get_csharp_function<void (CORECLR_DELEGATE_CALLTYPE*)()>(L"WinFormsTest.Program, WinFormsTest", L"Test1");
//调用
test1();
// .Test2的函数指针(方式2)
typedef void (CORECLR_DELEGATE_CALLTYPE* test2_fn)(Vec3);
test2_fn test2;
rew_bind_csharp_function(L"WinFormsTest.Program, WinFormsTest", L"Test2", (void**)&test2);
//调用
Vec3 vec = {1.0f, 2.0f, 3.0f};
test2(vec);
// 传递函数指针(方式3)
auto setptr = rew_get_csharp_function<void (CORECLR_DELEGATE_CALLTYPE*)(void*)>(L"WinFormsTest.Program, WinFormsTest", L"SetFuncPtr");
//调用
setptr((void*)& cpptest);
// 运行Main
run_app_fptr(cxt);
}
std::wcout << "成功结束" << std::endl;
close_fptr(cxt);
return EXIT_SUCCESS;
}
}
/********************************************************************************************
* 加载和激活.NET Core 所用的函数
********************************************************************************************/
namespace
{
//自定义的函数:绑定C#函数
template<typename T>
T rew_get_csharp_function(const char_t* type_name, const char_t* method_name)
{
T fptr;
int returncode = get_function_pointer(
type_name,
method_name,
UNMANAGEDCALLERSONLY_METHOD,
nullptr, nullptr, (void**)&fptr);
assert(returncode == 0 && fptr != nullptr && "Failure: get_function_pointer()");
return fptr;
}
//自定义的函数:获取C#函数
void rew_bind_csharp_function(const char_t* type_name, const char_t* method_name, void** del)
{
int returncode = get_function_pointer(
type_name,
method_name,
UNMANAGEDCALLERSONLY_METHOD,
nullptr, nullptr, del);
assert(returncode == 0 && del != nullptr && "Failure: get_function_pointer()");
}
}
namespace
{
//前向声明
void* load_library(const char_t*);
void* get_export(void*, const char*);
//载入库
void* load_library(const char_t* path)
{
HMODULE h = ::LoadLibraryW(path);
assert(h != nullptr);
return (void*)h;
}
void* get_export(void* h, const char* name)
{
void* f = ::GetProcAddress((HMODULE)h, name);
assert(f != nullptr);
return f;
}
// 使用 nethost 库,发现 hostfxr 的位置并获取导出
bool load_hostfxr(const char_t* assembly_path)
{
//get_hostfxr的参数
get_hostfxr_parameters params
{
sizeof(get_hostfxr_parameters),
assembly_path,
dotnet_root
};
//预分配内存来存储路径
char_t buffer[MAX_PATH];
size_t buffer_size = sizeof(buffer) / sizeof(char_t);
int rc = get_hostfxr_path(buffer, &buffer_size, ¶ms);
if (rc != 0)
return false;
// 加载 hostfxr(.NET 托管框架解析器)并获取所需的导出函数
// (注意:.NET 运行时不支持卸载其任何本机库。在任何 .NET 库上运行 dlclose/FreeLibrary 都会产生未定义的行为。)
void* lib = load_library(buffer);
init_for_cmd_line_fptr = (hostfxr_initialize_for_dotnet_command_line_fn)get_export(lib, "hostfxr_initialize_for_dotnet_command_line");//>>>>>>
init_for_config_fptr = (hostfxr_initialize_for_runtime_config_fn)get_export(lib, "hostfxr_initialize_for_runtime_config");
get_delegate_fptr = (hostfxr_get_runtime_delegate_fn)get_export(lib, "hostfxr_get_runtime_delegate");
run_app_fptr = (hostfxr_run_app_fn)get_export(lib, "hostfxr_run_app");
close_fptr = (hostfxr_close_fn)get_export(lib, "hostfxr_close");
return (init_for_config_fptr && get_delegate_fptr && close_fptr);
}
// (供load_component_example调用)加载和初始化.NET Core并获取场景所需的函数指针
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* config_path)
{
// 加载 .NET Core
void* load_assembly_and_get_function_pointer = nullptr;
hostfxr_handle cxt = nullptr;
int rc = init_for_config_fptr(config_path, nullptr, &cxt);
if (rc != 0 || cxt == nullptr)
{
std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return nullptr;
}
// 载入程序集获取函数指针
rc = get_delegate_fptr(
cxt,
hdt_load_assembly_and_get_function_pointer,
&load_assembly_and_get_function_pointer);
if (rc != 0 || load_assembly_and_get_function_pointer == nullptr)
std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
}
}
(END)