zhouqijie

代码示例



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, &params);

        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)