这是调用本机C++;使用CMAKE通过CLI/CLR在C#中编写代码 我创建了一个简单、干净、完整的例子,如何在CLI中封装一个本地C++ DLL,将它与C语言进行接口,并用CGUID构建整个过程。您可以使用CMAKE和visualstudio构建它(由于整个CLR的原因)
这是对这篇文章()的回应,它提供了一种方法,但并没有一个完整的测试答案。这主要基于()这个例子和自述文件中引用的代码项目中的例子 如果您喜欢性能(或者只是有遗留代码),并且希望构建一些DLL来与C#GUI或Unity游戏引擎或其他插件引擎接口,那么这可能很重要。我看到了一个很好的例子,你有一些矩阵代码,利用了Eigen,并希望在Unity或其他方面得到它。因此,您需要混合项目,因为您不希望每次Microsoft发布新版本的Visual Studio时都不断地创建一些内容这是调用本机C++;使用CMAKE通过CLI/CLR在C#中编写代码 我创建了一个简单、干净、完整的例子,如何在CLI中封装一个本地C++ DLL,将它与C语言进行接口,并用CGUID构建整个过程。您可以使用CMAKE和visualstudio构建它(由于整个CLR的原因),c#,c++,cmake,c++-cli,clr,C#,C++,Cmake,C++ Cli,Clr,这是对这篇文章()的回应,它提供了一种方法,但并没有一个完整的测试答案。这主要基于()这个例子和自述文件中引用的代码项目中的例子 如果您喜欢性能(或者只是有遗留代码),并且希望构建一些DLL来与C#GUI或Unity游戏引擎或其他插件引擎接口,那么这可能很重要。我看到了一个很好的例子,你有一些矩阵代码,利用了Eigen,并希望在Unity或其他方面得到它。因此,您需要混合项目,因为您不希望每次Microsoft发布新版本的Visual Studio时都不断地创建一些内容 此项目是一个玩具实例,但
此项目是一个玩具实例,但完成的是将事物从本机代码转移到托管CLR代码,以及C++和C语言中的测试。 我的问题是:这是像这样移动数据的最佳方式吗?你会用另一种方法吗?如果会,你会如何修改这个例子
对更复杂的类型示例有兴趣吗 本机DLL#pragma once
#include <vector>
#ifdef EXAMPLEUNMANAGEDDLL_EXPORTS
#define EXAMPLEUNMANAGEDDLL_API __declspec(dllexport)
#else
#define EXAMPLEUNMANAGEDDLL_API __declspec(dllimport)
#endif
class EXAMPLEUNMANAGEDDLL_API NativeEntity {
public:
NativeEntity();
//gets
std::string GetString();
std::vector<double> GetVector();
//sets
void SetString(std::string nString);
void SetVector(std::vector<double> &nVec);
private:
std::string mString;
std::vector<double> mVec;
}
C#Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityLibrary;
namespace SimpleClient
{
class Program
{
static void Main(string[] args)
{
var entity = new ManagedEntity();
string myString = "c# empty string";
double[] myArray = { -1.1, -2.1, -3.1 };
//Test String
System.Console.WriteLine("C# - Value for string: {0}", myString);
System.Console.WriteLine("C# - C++ Value stored for the string: {0}", entity.GetString());
myString = entity.GetString();
System.Console.WriteLine("C# - Value for string after GetString: {0}", myString);
entity.SetString("one-hundred point two");
System.Console.WriteLine("C# - C++ Value stored for the string: {0} \n", entity.GetString());
//Test Array
System.Console.WriteLine("C# - Value for array: {0}", string.Join(", ", myArray));
System.Console.WriteLine("C# - C++ Value stored for the string: {0}", string.Join(", ", entity.GetVector()));
myArray = entity.GetVector();
System.Console.WriteLine("C# - Value for array after GetVector: {0}", string.Join(", ", myArray));
entity.SetVector(new double[] { 100.1, 100.2, 100.3, 100.4 });
System.Console.WriteLine("C# - C++ Value stored for the string: {0}", string.Join(", ", entity.GetVector()));
//array,comma trick needs .NET 4+ if it does not work use code below to print array to console
// foreach (var item in myArray)
// {
// Console.Write("{0}", item);
// if (item != myArray.Last())
// Console.Write(",");
// }
}
}
}
现在,这就是它变得骇人听闻的地方
所以我添加了一个特殊的模板Csharp_Test_Application.csproj.template
让下面的CMAKE main CMakeLists.txt阅读
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProjectGuid>{349769A5-261C-4234-BC48-F558817438F0}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Csharp_Test_Application</RootNamespace>
<AssemblyName>Csharp_Test_Application</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<PlatformTarget>x64</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\Release</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="CLI_Bridge, Version=1.0.6179.18199, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\Release\CLI_Bridge.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="${DOS_STYLE_SOURCE_DIR}\**\*.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
建议将您正在谈论的数据添加到问题中,不要指望github链接。好主意!将代码添加到帖子本身,以帮助人们了解我在做什么。代码仍然在github上,以使人们更容易运行该示例,但我明白了。。。这样也就永远存在了。建议将您正在谈论的数据添加到问题中,不要指望github链接。好主意!将代码添加到帖子本身,以帮助人们了解我在做什么。代码仍然在github上,以使人们更容易运行该示例,但我明白了。。。这条路永远在这里。
#include "ManagedEntity.h"
using namespace EntityLibrary;
using namespace System;
using namespace System::Runtime::InteropServices; // needed for Marshal
ManagedEntity::ManagedEntity() {
nativeObj = new NativeEntity();
}
ManagedEntity::~ManagedEntity() {
delete nativeObj;
}
String^ ManagedEntity::GetString()
{
String^ tempString = gcnew String( nativeObj->GetString().c_str());
return tempString;
}
array<double>^ ManagedEntity::GetVector()
{
std::vector<double> tempVec = nativeObj->GetVector();
const int SIZE = tempVec.size();
array<double> ^tempArr = gcnew array<double>(SIZE);
for (int i = 0; i < SIZE; i++)
{
tempArr[i] = tempVec[i];
}
return tempArr;
}
void ManagedEntity::SetString(String^ nString)
{
IntPtr pString = Marshal::StringToHGlobalAnsi(nString);
try
{
char* pchString = static_cast<char *>(pString.ToPointer());
nativeObj->SetString(pchString);
}
finally
{
Marshal::FreeHGlobal(pString);
}
}
void ManagedEntity::SetVector(array<double>^ nVec)
{
std::vector<double> tempVec;
for each (double elem in nVec)
tempVec.push_back(elem);
nativeObj->SetVector(tempVec);
}
using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security::Permissions;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly:AssemblyTitleAttribute("EntityLibrary")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyCompanyAttribute("EMC")];
[assembly:AssemblyProductAttribute("EntityLibrary")];
[assembly:AssemblyCopyrightAttribute("Copyright (c) EMC 2007")];
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the value or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly:AssemblyVersionAttribute("1.0.*")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityLibrary;
namespace SimpleClient
{
class Program
{
static void Main(string[] args)
{
var entity = new ManagedEntity();
string myString = "c# empty string";
double[] myArray = { -1.1, -2.1, -3.1 };
//Test String
System.Console.WriteLine("C# - Value for string: {0}", myString);
System.Console.WriteLine("C# - C++ Value stored for the string: {0}", entity.GetString());
myString = entity.GetString();
System.Console.WriteLine("C# - Value for string after GetString: {0}", myString);
entity.SetString("one-hundred point two");
System.Console.WriteLine("C# - C++ Value stored for the string: {0} \n", entity.GetString());
//Test Array
System.Console.WriteLine("C# - Value for array: {0}", string.Join(", ", myArray));
System.Console.WriteLine("C# - C++ Value stored for the string: {0}", string.Join(", ", entity.GetVector()));
myArray = entity.GetVector();
System.Console.WriteLine("C# - Value for array after GetVector: {0}", string.Join(", ", myArray));
entity.SetVector(new double[] { 100.1, 100.2, 100.3, 100.4 });
System.Console.WriteLine("C# - C++ Value stored for the string: {0}", string.Join(", ", entity.GetVector()));
//array,comma trick needs .NET 4+ if it does not work use code below to print array to console
// foreach (var item in myArray)
// {
// Console.Write("{0}", item);
// if (item != myArray.Last())
// Console.Write(",");
// }
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProjectGuid>{349769A5-261C-4234-BC48-F558817438F0}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Csharp_Test_Application</RootNamespace>
<AssemblyName>Csharp_Test_Application</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<PlatformTarget>x64</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\Release</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="CLI_Bridge, Version=1.0.6179.18199, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>${CMAKE_RUNTIME_OUTPUT_DIRECTORY}\Release\CLI_Bridge.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="${DOS_STYLE_SOURCE_DIR}\**\*.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
cmake_minimum_required(VERSION 2.8.9)
project("CLI_DLL_Bridge_Test")
##############################################################
# Output paths
##############################################################
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
set(NATIVEENTITY_INCLUDE_DIR
${CMAKE_CURRENT_SOURCE_DIR}/UnmanagedNativeDLL)
add_subdirectory(UnmanagedNativeDLL)
add_subdirectory(CLI_DLL_Bridge)
add_subdirectory(UnmanagedNativeTest_Application)
# C# Project MumboJumbo Hack
SET(CSHARP_PROJECT "Csharp_Test_Application")
SET(CSHARP_PROJECT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Csharp_Test_Application")
MESSAGE( STATUS "Copying in C# Project: " ${CSHARP_PROJECT} )
MESSAGE( STATUS "from directory: " ${CSHARP_PROJECT_DIRECTORY} )
FILE(TO_NATIVE_PATH "${CSHARP_PROJECT_DIRECTORY}" DOS_STYLE_SOURCE_DIR)
include_external_msproject(
${CSHARP_PROJECT} ${CSHARP_PROJECT}.csproj
TYPE FAE04EC0-301F-11D3-BF4B-00C04F79EFBC CLI_Bridge NativeEntity)
CONFIGURE_FILE(${CSHARP_PROJECT_DIRECTORY}/${CSHARP_PROJECT}.csproj.template ${CSHARP_PROJECT}.csproj)