我做了一个C++CLI包装器,用于在C++应用程序中使用C# DLL。我使用Visual Studio来管理项目和管理依赖关系,并且我用这种方式让它工作。
但是当我使用CMake来链接Visual Studio为我建立的库时,我无法让它工作。
cmake_minimum_required (VERSION 3.12)
project(playground CXX)
SET(CMAKE_CXX_STANDARD 17)
set(PLAYGROUND_SOURCE_DIR ${CCMAKE_CURRENT_SOURCE_DIR})
set(PLAYGROUND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(PLAYGROUND_SRC
main.cpp)
add_executable(Playground ${PLAYGROUND_SRC} ${PLAYGROUND_HDR})
find_library(comm_dll CommWrapper Lib/CommDLL)
target_link_libraries(Playground PUBLIC
${comm_dll}
)
使用这种方法会得到一个 "未解决的外部符号错误"。我把.dll,.lib和.h文件放在同一个文件夹里。
正如Hans Passant已经说过的那样:你必须将你的C++CLI代码编译成动态库,才能从一个未管理的应用程序中消耗它。CLIM管理的代码不能从不能驻留在静态库中运行。如果你把C++CLI库目标从静态库改成动态库,你就可以成功地编译你的非托管C++应用程序。
我的一个想法是:我认为你最好使用混合模式的C++CLI DLLs来使用托管功能--你将能够使你的消费者应用程序完全摆脱对CLR的引用。
Element类的这种混合模式Wrapper的Header应该是这样的。
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
而实现则是这样的
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
然后只需将 Element.cpp + ElementWrapper.cpp 编译成 DLL,然后在你的非托管应用程序中使用 ElementWrapper.h。