C++调用C#代码的几种方法总结

方法一、使用 C++/CLI 创建一个桥接库

返回基础数据类型:

1.首先我们新建 一个C#的类库工程 CSharpLib

新建一个ExportClass类,增加一个GetID函数,如下:

1 public class ExplortClass
2     {
3         public int GetID()
4         {
5             return 1024;
6         }
7     }

2.新建一个CLR空工程CSBridge,这个库会作为中间桥接的库。将CSBridge工程的输出路径修改为CSharpLib工程的输出路径

说明:如果没有看到CLR Empty,可以到Visual Studio的安装程序中钩选并安装(直接搜索cli)

 新建一个bridge.cpp。输入以下代码

 1 #include <Windows.h>
 2 #include<msclr/marshal_cppstd.h>
 3 
 4 //引用C# dll
 5 #using "./CSharpLib.dll"
 6 
 7 //引用命名空间
 8 using namespace msclr::interop;
 9 using namespace System;
10 using namespace System::Runtime::InteropServices;
11 using namespace CSharpLib;
12 
13 #define lib_export
14 #ifdef lib_export
15 #define cs_lib_api extern "C" __declspec(dllexport)
16 #else
17 #define cs_lib_api __declspec(dllimport)
18 #endif
19 
20 typedef int(__stdcall* funGetId)();  //定义函数指针
21 
22 //导出函数 供C++调用
23 //在这个函数里调用 C#的函数,做为中转层
24 cs_lib_api int GetID()
25 {
26     CSharpLib::ExplortClass^ c = gcnew CSharpLib::ExplortClass();
27     auto id = c->GetID();
28     return id;
29 }

这样就拥有了一个桥接工程 。

3. 新建一个C++控制台应用程序,输入以下代码测试。

// CppInvoke.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include<Windows.h>

typedef int(__stdcall* funGetId)();

int main()
{
    HMODULE hInstance = LoadLibrary(L"CSBridge.dll");
    if (hInstance)
    {
        funGetId getId = (funGetId)GetProcAddress(hInstance, "GetID");

        if (getId)
        {
            auto result = getId();
            std::cout << result << std::endl;
        }
    }
}

可以看到输出结果为:1024

复杂一点的情况,返回一个结构体:

在CSharpLib中增加一个结构体Computer:

1     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
2     public struct Computer
3     {
4         public int cpuId; 
5         public string cpuName;
6         public int osVersion;
7     }

增加一个获取Computer的函数

1   public Computer GetComputer()
2         {
3             Computer computer = new Computer();
4             computer.cpuId = 100000000;
5             computer.cpuName = "Intel";
6             computer.osVersion = 11;
7             return computer;
8         }

 然后在CSBridge中增加一个用于和Computer交互的类型interop_Computer,这个类型是用于C++中调用时使用,使用C#中的Computer类型转换可以得到interop_Computer。

1 struct interop_Computer
2 {
3     int cpuId;
4     wchar_t* cpuName;
5     int osVersion;
6 };

 再定义一个函数指针和增加一个中转层函数

 1 typedef interop_Computer(__stdcall* funGetComputer)();
 2 
 3 cs_lib_api interop_Computer GetComputer()
 4 {
 5     CSharpLib::ExplortClass^ c = gcnew CSharpLib::ExplortClass();
 6     auto computer = c->GetComputer(); //调用C#中的函数
 7     System::IntPtr ptr = Marshal::AllocHGlobal(sizeof(interop_Computer));//需要提前分配空间
 8     System::Runtime::InteropServices::Marshal::StructureToPtr(computer, ptr, false);//将C#中的结构体拷贝到Intptr
 9     interop_Computer* rt = (interop_Computer*)(void*)(ptr.ToPointer());//将Intptr强制转换为interop_Computer
10     return *rt;
11 }

 然后在CppInvoke中添加测试代码

HMODULE hInstance = LoadLibrary(L"CSBridge.dll");
    if (hInstance)
    {
      
        funGetComputer getComputer = (funGetComputer)GetProcAddress(hInstance, "GetComputer");
         
        if (getComputer)
        {
            auto computer = getComputer();
            std::wcout << computer.cpuId << "\t" << computer.cpuName << "\t" << computer.osVersion << std::endl;
        }

        FreeLibrary(hInstance);
    }

输出结果为:

这里还有一种情况,就 是需要 将C++中的参数传到C#中。

 这种情况有两种方法可以实现:

1、将C++中的参数封送到C#中,转换方式和上面返回结构体的实现方式差不多。大概思路就是把C++结构体转换成IntPtr,再从IntPtr转换到C#中的结构体。

2、将C#中的函数转换到C++中的函数再调用。这样就可以直接使用C++中的结构体。

实现方法如下:

在C#中增加一个函数PrintComputer,需要传入一个Computer结构体。然后再增加对应的委托和获取委托的函数

1 public void PrintComputer(Computer computer)
2         {
3             Console.WriteLine(computer.cpuId);
4             Console.WriteLine(computer.cpuName);
5             Console.WriteLine(computer.osVersion);
6         }

1 public delegate void PrintComputerDelegate(Computer computer); //声明委托
2 
4 public PrintComputerDelegate GetComputerDelegate() => PrintComputer;  //定义返回委托的函数

 在CSBridge中定义一个函数指针,并增加一个导出函数

 1 typedef void(__stdcall* funPrintComputer)(interop_Computer computer);
 2 
 3 cs_lib_api void PrintComputer(interop_Computer computer)
 4 {
 5     CSharpLib::ExplortClass^ c = gcnew CSharpLib::ExplortClass();
 6     auto printDelegate = c->GetComputerDelegate();//获取委托 
 7     IntPtr ptr = Marshal::GetFunctionPointerForDelegate(printDelegate);//将委托转为IntPtr类型
 8     funPrintComputer funcPrint = (funPrintComputer)ptr.ToPointer();//将IntPtr转换为指针,再转换为funPrintComputer
 9     if (funcPrint)
10     {
11         funcPrint(computer);
12     }
13 }

 这样就可以在C++中的参数传递到C#中。CppInvoke中的调用 代码如下:

1 funPrintComputer printComputer = (funPrintComputer)GetProcAddress(hInstance, "PrintComputer");
2         interop_Computer testComputer;
3         testComputer.cpuId = 18;
4         testComputer.cpuName = _tcsdup(L"AMD");
5         testComputer.osVersion = 7;
6         if (printComputer)
7         {
8             printComputer(testComputer);
9         }

 输出结果为:

示例代码(需要Visual Studio 2022)

方法二、将.NET组件导出为COM

待完成

### 若依框架中 `v-hasPermi` 的配置方法及位置 #### 一、`v-hasPermi` 的基本概念 `v-hasPermi` 是若依框架中的自定义指令,用于实现前端权限控制功能。它通过绑定用户的权限列表与页面上的按钮或菜单项进行匹配,从而决定是否渲染对应的 DOM 元素[^1]。 #### 二、`v-hasPermi` 的配置位置 在若依框架中,`v-hasPermi` 的核心逻辑通常位于项目的 **permission.js** 文件中。该文件负责封装权限校验的核心逻辑,并将其注册为 Vue 的全局指令。以下是具体的路径和结构: - 路径: `/src/utils/permission.js` - 功能描述: 此文件实现了权限校验的逻辑,并将 `v-hasPermi` 注册为 Vue 指令[^2]。 #### 三、`v-hasPermi` 的实现方式 以下是 `v-hasPermi` 实现的关键代码片段及其说明: ```javascript // 导入权限校验函数 import hasPermi from './permission/hasPermi'; const install = function(Vue) { // 定义 v-hasPermi 指令 Vue.directive('hasPermi', { inserted: function(el, binding) { const permissions = binding.value; if (!Array.isArray(permissions)) { console.error(`v-hasPermi value must be an array! Like v-hasPermi="['admin','user']"`); el.parentNode && el.parentNode.removeChild(el); return; } // 使用 hasPermi 函数校验权限 if (!hasPermi(permissions)) { el.parentNode && el.parentNode.removeChild(el); // 如果无权限,则移除元素 } }, update: function(el, binding) { const permissions = binding.value; if (!Array.isArray(permissions)) { console.error(`v-hasPermi value must be an array! Like v-hasPermi="['admin','user']"`); el.parentNode && el.parentNode.removeChild(el); return; } if (!hasPermi(permissions)) { el.parentNode && el.parentNode.removeChild(el); } } }); }; if (window.Vue) { window['hasPermi'] = hasPermi; } export default install; ``` 上述代码展示了如何将 `v-hasPermi` 注册为 Vue 的全局指令,并在其生命周期钩子(inserted 和 update)中调用权限校验函数 `hasPermi()` 来动态隐藏或显示元素。 #### 四、`v-hasPermi` 的使用场景 `v-hasPermi` 主要应用于需要根据用户权限动态展示的功能模块上。例如,在按钮控件中可以通过如下方式进行权限控制: ```html <el-button v-hasPermi="['managementDocument-note-add']" type="primary" @click="openDialog">新增文档</el-button> ``` 在此示例中,只有当当前登录用户拥有 `'managementDocument-note-add'` 权限时,才会渲染此按钮[^3]。 #### 五、特殊情况处理 对于一些无法直接使用 `v-hasPermi` 的场景(如 `<template>` 或其他特殊组件),可以改用全局权限判断函数 `checkPermi([])` 进行逻辑控制。例如: ```html <el-button size="mini" type="text" icon="el-icon-edit-outline" v-if="scope.row.approveStatus === '2' && checkPermi(['evaluation:user:his'])" @click="handleHis(scope.row)">评分记录</el-button> ``` 在这种情况下,`checkPermi([])` 提供了更灵活的权限校验能力[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

△曉風殘月〆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值