当前位置: 代码网 > it编程>编程语言>Asp.net > C++与.NET之间的互相调用的几种常见方式

C++与.NET之间的互相调用的几种常见方式

2025年07月11日 Asp.net 我要评论
c++ 与 .net 之间的互操作性是开发混合应用程序时的常见需求。下面我将展示几种常见的互操作方式和示例:1. 使用 c++/cli 作为桥梁c++/cli 是微软提供的一种中间语言,专门用于连接原

c++ 与 .net 之间的互操作性是开发混合应用程序时的常见需求。下面我将展示几种常见的互操作方式和示例:

1. 使用 c++/cli 作为桥梁

c++/cli 是微软提供的一种中间语言,专门用于连接原生 c++ 和 .net 代码。这是实现互操作性最灵活的方式。

cpp-dotnet-interop c++/cli 互操作代码示例

nativelibrary.h - 原生 c++ 库

// nativelibrary.h - 原生 c++ 库
#pragma once

extern "c" {
    __declspec(dllexport) int add(int a, int b);
    __declspec(dllexport) void* createperson(const char* name, int age);
    __declspec(dllexport) const char* getpersonname(void* person);
    __declspec(dllexport) int getpersonage(void* person);
    __declspec(dllexport) void destroyperson(void* person);
}

nativelibrary.cpp - 原生 c++ 库实现

// nativelibrary.cpp - 原生 c++ 库实现
#include "nativelibrary.h"
#include <string>
#include <memory>

// 简单的 person 类
struct person {
    std::string name;
    int age;
};

int add(int a, int b) {
    return a + b;
}

void* createperson(const char* name, int age) {
    auto person = new person{name, age};
    return person;
}

const char* getpersonname(void* person) {
    return reinterpret_cast<person*>(person)->name.c_str();
}

int getpersonage(void* person) {
    return reinterpret_cast<person*>(person)->age;
}

void destroyperson(void* person) {
    delete reinterpret_cast<person*>(person);
}

bridgelibrary.h - c++/cli 桥接头文件

// bridgelibrary.h - c++/cli 桥接头文件
#pragma once

using namespace system;

namespace bridgelibrary {
    public ref class calculator {
    public:
        static int add(int a, int b);
    };

    public ref class personwrapper {
    private:
        void* nativeperson;

    public:
        personwrapper(string^ name, int age);
        ~personwrapper();
        !personwrapper();

        string^ getname();
        int getage();
    };
}

bridgelibrary.cpp - c++/cli 桥接实现

// bridgelibrary.cpp - c++/cli 桥接实现
#include "bridgelibrary.h"
#include "../nativelibrary/nativelibrary.h"
#include <msclr/marshal_cppstd.h>

namespace bridgelibrary {
    int calculator::add(int a, int b) {
        return ::add(a, b);
    }

    personwrapper::personwrapper(string^ name, int age) {
        msclr::interop::marshal_context context;
        const char* nativename = context.marshal_as<const char*>(name);
        nativeperson = ::createperson(nativename, age);
    }

    personwrapper::~personwrapper() {
        this->!personwrapper();
    }

    personwrapper::!personwrapper() {
        if (nativeperson != nullptr) {
            ::destroyperson(nativeperson);
            nativeperson = nullptr;
        }
    }

    string^ personwrapper::getname() {
        const char* nativename = ::getpersonname(nativeperson);
        return gcnew string(nativename);
    }

    int personwrapper::getage() {
        return ::getpersonage(nativeperson);
    }
}

dotnetclient.cs - .net 客户端调用示例

// dotnetclient.cs - .net 客户端调用示例
using system;
using bridgelibrary;

class program {
    static void main() {
        // 调用 c++ 计算函数
        int result = calculator.add(5, 3);
        console.writeline("5 + 3 = " + result);

        // 使用 c++ 中的 person 类
        using (var person = new personwrapper("john doe", 30)) {
            console.writeline("name: " + person.getname());
            console.writeline("age: " + person.getage());
        }
    }
}

2. 使用 p/invoke 从 .net 调用原生 c++

如果不想使用 c++/cli,也可以通过 p/invoke 直接从 .net 调用原生 c++ 函数。

cpp-dotnet-pinvoke p/invoke调用代码示例

nativelibrary.h - 原生 c++ 库

// nativelibrary.h - 原生 c++ 库
#pragma once

extern "c" {
    __declspec(dllexport) int add(int a, int b);
    __declspec(dllexport) void* createperson(const char* name, int age);
    __declspec(dllexport) const char* getpersonname(void* person);
    __declspec(dllexport) int getpersonage(void* person);
    __declspec(dllexport) void destroyperson(void* person);
}

nativelibrary.cpp - 原生 c++ 库实现

// nativelibrary.cpp - 原生 c++ 库实现
#include "nativelibrary.h"
#include <string>
#include <memory>

// 简单的 person 类
struct person {
    std::string name;
    int age;
};

int add(int a, int b) {
    return a + b;
}

void* createperson(const char* name, int age) {
    auto person = new person{name, age};
    return person;
}

const char* getpersonname(void* person) {
    return reinterpret_cast<person*>(person)->name.c_str();
}

int getpersonage(void* person) {
    return reinterpret_cast<person*>(person)->age;
}

void destroyperson(void* person) {
    delete reinterpret_cast<person*>(person);
}

dotnetclient.cs - .net 客户端 p/invoke 调用示例

// dotnetclient.cs - .net 客户端 p/invoke 调用示例
using system;
using system.runtime.interopservices;

class program {
    // 导入原生 c++ 函数
    [dllimport("nativelibrary.dll", callingconvention = callingconvention.cdecl)]
    public static extern int add(int a, int b);

    [dllimport("nativelibrary.dll", callingconvention = callingconvention.cdecl)]
    public static extern intptr createperson(string name, int age);

    [dllimport("nativelibrary.dll", callingconvention = callingconvention.cdecl)]
    [return: marshalas(unmanagedtype.lpstr)]
    public static extern string getpersonname(intptr person);

    [dllimport("nativelibrary.dll", callingconvention = callingconvention.cdecl)]
    public static extern int getpersonage(intptr person);

    [dllimport("nativelibrary.dll", callingconvention = callingconvention.cdecl)]
    public static extern void destroyperson(intptr person);

    static void main() {
        // 调用 c++ 计算函数
        int result = add(5, 3);
        console.writeline("5 + 3 = " + result);

        // 使用 c++ 中的 person 类
        intptr personptr = createperson("john doe", 30);
        try {
            string name = getpersonname(personptr);
            int age = getpersonage(personptr);
            console.writeline("name: " + name);
            console.writeline("age: " + age);
        }
        finally {
            // 释放资源
            destroyperson(personptr);
        }
    }
}

3. 从 c++ 调用 .net 代码

从原生 c++ 调用 .net 代码需要使用 clr hosting api。下面是一个简单的示例:

cpphost.cpp - c++ 调用 .net 代码示例

// cpphost.cpp - c++ 调用 .net 代码示例
#include <windows.h>
#include <metahost.h>
#include <string>
#include <iostream>

#pragma comment(lib, "mscoree.lib")

int main() {
    // 初始化 clr
    iclrmetahost* pmetahost = nullptr;
    iclrruntimeinfo* pruntimeinfo = nullptr;
    iclrruntimehost* pclrruntimehost = nullptr;

    hresult hr = clrcreateinstance(clsid_clrmetahost, iid_iclrmetahost, (lpvoid*)&pmetahost);
    if (failed(hr)) {
        std::cerr << "failed to create clr instance" << std::endl;
        return 1;
    }

    hr = pmetahost->getruntime(l"v4.0.30319", iid_iclrruntimeinfo, (lpvoid*)&pruntimeinfo);
    if (failed(hr)) {
        std::cerr << "failed to get runtime info" << std::endl;
        pmetahost->release();
        return 1;
    }

    bool floadable;
    hr = pruntimeinfo->isloadable(&floadable);
    if (failed(hr) || !floadable) {
        std::cerr << "runtime is not loadable" << std::endl;
        pruntimeinfo->release();
        pmetahost->release();
        return 1;
    }

    hr = pruntimeinfo->getinterface(clsid_clrruntimehost, iid_iclrruntimehost, (lpvoid*)&pclrruntimehost);
    if (failed(hr)) {
        std::cerr << "failed to get runtime host" << std::endl;
        pruntimeinfo->release();
        pmetahost->release();
        return 1;
    }

    hr = pclrruntimehost->start();
    if (failed(hr)) {
        std::cerr << "failed to start clr" << std::endl;
        pclrruntimehost->release();
        pruntimeinfo->release();
        pmetahost->release();
        return 1;
    }

    // 调用 .net 方法
    dword preturnvalue;
    hr = pclrruntimehost->executeindefaultappdomain(
        l"dotnetlibrary.dll",
        l"dotnetlibrary.calculator",
        l"add",
        l"5,3",
        &preturnvalue);

    if (failed(hr)) {
        std::cerr << "failed to execute .net method" << std::endl;
    } else {
        std::cout << "result from .net: " << preturnvalue << std::endl;
    }

    // 清理资源
    pclrruntimehost->stop();
    pclrruntimehost->release();
    pruntimeinfo->release();
    pmetahost->release();

    return 0;
}

dotnetlibrary.cs - .net 库示例

// dotnetlibrary.cs - .net 库示例
namespace dotnetlibrary {
    public class calculator {
        public static int add(string args) {
            string[] numbers = args.split(',');
            int a = int.parse(numbers[0]);
            int b = int.parse(numbers[1]);
            return a + b;
        }
    }
}

互操作方法比较

  1. c++/cli

    • 优点:完全支持 .net 功能,可直接访问 .net 类库
    • 缺点:需要安装 .net framework/.net core
    • 适用场景:需要深度集成 .net 功能的 c++ 应用
  2. p/invoke

    • 优点:简单直接,不需要中间层
    • 缺点:类型映射复杂,不支持面向对象特性
    • 适用场景:从 .net 调用简单的 c/c++ 函数
  3. clr hosting

    • 优点:允许原生 c++ 代码调用 .net 代码
    • 缺点:实现复杂,性能开销大
    • 适用场景:需要在 c++ 应用中嵌入 .net 功能

 到此这篇关于c++与.net之间的互相调用的几种常见方式的文章就介绍到这了,更多相关c++ .net互相调用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com