C++與.NET之間的互相調(diào)用的幾種常見(jiàn)方式
C++ 與 .NET 之間的互操作性是開(kāi)發(fā)混合應(yīng)用程序時(shí)的常見(jiàn)需求。下面我將展示幾種常見(jiàn)的互操作方式和示例:
1. 使用 C++/CLI 作為橋梁
C++/CLI 是微軟提供的一種中間語(yǔ)言,專(zhuān)門(mén)用于連接原生 C++ 和 .NET 代碼。這是實(shí)現(xiàn)互操作性最靈活的方式。
cpp-dotnet-interop C++/CLI 互操作代碼示例
NativeLibrary.h - 原生 C++ 庫(kù)
// NativeLibrary.h - 原生 C++ 庫(kù)
#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++ 庫(kù)實(shí)現(xiàn)
// NativeLibrary.cpp - 原生 C++ 庫(kù)實(shí)現(xiàn)
#include "NativeLibrary.h"
#include <string>
#include <memory>
// 簡(jiǎn)單的 Person 類(lèi)
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 橋接實(shí)現(xiàn)
// BridgeLibrary.cpp - C++/CLI 橋接實(shí)現(xiàn)
#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 客戶(hù)端調(diào)用示例
// DotNetClient.cs - .NET 客戶(hù)端調(diào)用示例
using System;
using BridgeLibrary;
class Program {
static void Main() {
// 調(diào)用 C++ 計(jì)算函數(shù)
int result = Calculator.Add(5, 3);
Console.WriteLine("5 + 3 = " + result);
// 使用 C++ 中的 Person 類(lèi)
using (var person = new PersonWrapper("John Doe", 30)) {
Console.WriteLine("Name: " + person.GetName());
Console.WriteLine("Age: " + person.GetAge());
}
}
}
2. 使用 P/Invoke 從 .NET 調(diào)用原生 C++
如果不想使用 C++/CLI,也可以通過(guò) P/Invoke 直接從 .NET 調(diào)用原生 C++ 函數(shù)。
cpp-dotnet-pinvoke p/Invoke調(diào)用代碼示例
NativeLibrary.h - 原生 C++ 庫(kù)
// NativeLibrary.h - 原生 C++ 庫(kù)
#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++ 庫(kù)實(shí)現(xiàn)
// NativeLibrary.cpp - 原生 C++ 庫(kù)實(shí)現(xiàn)
#include "NativeLibrary.h"
#include <string>
#include <memory>
// 簡(jiǎn)單的 Person 類(lèi)
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 客戶(hù)端 P/Invoke 調(diào)用示例
// DotNetClient.cs - .NET 客戶(hù)端 P/Invoke 調(diào)用示例
using System;
using System.Runtime.InteropServices;
class Program {
// 導(dǎo)入原生 C++ 函數(shù)
[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() {
// 調(diào)用 C++ 計(jì)算函數(shù)
int result = Add(5, 3);
Console.WriteLine("5 + 3 = " + result);
// 使用 C++ 中的 Person 類(lèi)
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++ 調(diào)用 .NET 代碼
從原生 C++ 調(diào)用 .NET 代碼需要使用 CLR Hosting API。下面是一個(gè)簡(jiǎn)單的示例:
CppHost.cpp - C++ 調(diào)用 .NET 代碼示例
// CppHost.cpp - C++ 調(diào)用 .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;
}
// 調(diào)用 .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 庫(kù)示例
// DotNetLibrary.cs - .NET 庫(kù)示例
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;
}
}
}
互操作方法比較
C++/CLI:
- 優(yōu)點(diǎn):完全支持 .NET 功能,可直接訪問(wèn) .NET 類(lèi)庫(kù)
- 缺點(diǎn):需要安裝 .NET Framework/.NET Core
- 適用場(chǎng)景:需要深度集成 .NET 功能的 C++ 應(yīng)用
P/Invoke:
- 優(yōu)點(diǎn):簡(jiǎn)單直接,不需要中間層
- 缺點(diǎn):類(lèi)型映射復(fù)雜,不支持面向?qū)ο筇匦?/li>
- 適用場(chǎng)景:從 .NET 調(diào)用簡(jiǎn)單的 C/C++ 函數(shù)
CLR Hosting:
- 優(yōu)點(diǎn):允許原生 C++ 代碼調(diào)用 .NET 代碼
- 缺點(diǎn):實(shí)現(xiàn)復(fù)雜,性能開(kāi)銷(xiāo)大
- 適用場(chǎng)景:需要在 C++ 應(yīng)用中嵌入 .NET 功能
到此這篇關(guān)于C++與.NET之間的互相調(diào)用的幾種常見(jiàn)方式的文章就介紹到這了,更多相關(guān)C++ .NET互相調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Cocos2d-x中獲取系統(tǒng)時(shí)間和隨機(jī)數(shù)實(shí)例
這篇文章主要介紹了Cocos2d-x中獲取系統(tǒng)時(shí)間和隨機(jī)數(shù)實(shí)例,本文代碼含有大量注釋來(lái)講解獲取系統(tǒng)時(shí)間和隨機(jī)數(shù)的方法,需要的朋友可以參考下2014-09-09
簡(jiǎn)單總結(jié)C語(yǔ)言中各種類(lèi)型的指針的概念
這篇文章主要簡(jiǎn)單總結(jié)了C語(yǔ)言中各種類(lèi)型的指針的概念,指針可以說(shuō)是C語(yǔ)言本身所具有的最大特性,平時(shí)根據(jù)不同使用場(chǎng)合習(xí)慣地將其簡(jiǎn)單分類(lèi),需要的朋友可以參考下2016-03-03
C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡(jiǎn)單實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡(jiǎn)單實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助大家實(shí)現(xiàn)優(yōu)先隊(duì)列,需要的朋友可以參考下2017-08-08

