这是调用本机C++;使用CMAKE通过CLI/CLR在C#中编写代码 我创建了一个简单、干净、完整的例子,如何在CLI中封装一个本地C++ DLL,将它与C语言进行接口,并用CGUID构建整个过程。您可以使用CMAKE和visualstudio构建它(由于整个CLR的原因)

这是调用本机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时都不断地创建一些内容 此项目是一个玩具实例,但

这是对这篇文章()的回应,它提供了一种方法,但并没有一个完整的测试答案。这主要基于()这个例子和自述文件中引用的代码项目中的例子

如果您喜欢性能(或者只是有遗留代码),并且希望构建一些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)