使用含托管类的C#/CLR .tlb文件对接C++/Qt是否可行?
可行方案指引
方案1:Visual Studio 分文件启用CLR(推荐,最简)
这个方案不需要拆分独立DLL,直接在同一个Qt项目里混合编译,解决你说的全项目开CLR导致Qt代码失效的问题。
- 前置准备:VS安装Qt VS Tools插件,创建标准Qt Widgets项目,确认原生Qt代码可以正常编译运行。
- 抽离CLR相关代码:把你调用TLB的逻辑单独拆成两个文件:
- 头文件
instrument_adapter.h(纯原生C++语法,无任何CLR相关关键字,可被Qt代码直接引用)
#ifndef INSTRUMENT_ADAPTER_H #define INSTRUMENT_ADAPTER_H #include <utility> class InstrumentAdapterPrivate; class InstrumentAdapter { public: InstrumentAdapter(); ~InstrumentAdapter(); std::pair<int, int> getXY(); private: InstrumentAdapterPrivate* d; // PIMPL不透明指针,隐藏CLR实现细节 }; #endif- 实现文件
instrument_adapter.cpp(仅这个文件开启CLR支持,包含CLR逻辑)
把你原来的托管类放在这个cpp里,实现适配器的逻辑:
#include "pch.h" #include "instrument_adapter.h" #include <chrono> #include <thread> using namespace System; // 托管类和私有实现都放在cpp内部,对外不可见 public ref class Instrument { public: TEMEXTLib::TEM3Class ^theScope; TEMEXTLib::IDef3^ theDef; Instrument() { theScope = gcnew TEMEXTLib::TEM3Class(); theDef = theScope->CreateDef3(); std::chrono::seconds timespan(2); std::this_thread::sleep_for(timespan); } std::pair<int, int> check() { int x; int y; theDef->GetCLA1(x, y); return {x, y}; } }; class InstrumentAdapterPrivate { public: gcroot<Instrument^> instance; // gcroot用来在原生类里持有托管对象引用 }; InstrumentAdapter::InstrumentAdapter() : d(new InstrumentAdapterPrivate()) { d->instance = gcnew Instrument(); } InstrumentAdapter::~InstrumentAdapter() { delete d; } std::pair<int, int> InstrumentAdapter::getXY() { return d->instance->check(); } - 头文件
- 单文件编译配置:右键点击
instrument_adapter.cpp-> 属性 -> 【C/C++】-> 【常规】-> 【公共语言运行时支持】选择公共语言运行时支持(/clr),其他所有文件保持默认的无CLR配置即可。 - 冲突解决:给
instrument_adapter.cpp单独关闭【C/C++】-> 【代码生成】-> 【基本运行时检查】设置为默认值,运行库选多线程调试DLL(/MDd)(和Qt项目配置保持一致)。 - 对接Qt:你直接在Qt的窗口类里引用
instrument_adapter.h,创建InstrumentAdapter实例,调用getXY()拿到x、y值后,用QString("X值:%1,Y值:%2").arg(x).arg(y)拼接字符串,调用QLabel::setText()即可展示。
方案2:CLR逻辑编译为独立DLL(兼容性最好)
如果需要用Qt Creator开发,或者后续要做跨平台适配,选这个方案:
- 单独创建一个VS动态库项目,开启CLR支持,把你调用TLB的逻辑封装成纯C接口导出:
// dllmain.cpp 或者单独的导出文件 extern "C" __declspec(dllexport) void* create_instrument() { auto ins = gcnew Instrument(); return GCHandle::ToIntPtr(GCHandle::Alloc(ins)).ToPointer(); } extern "C" __declspec(dllexport) void get_instrument_xy(void* ins, int* x, int* y) { GCHandle handle = GCHandle::FromIntPtr(IntPtr(ins)); Instrument^ instance = safe_cast<Instrument^>(handle.Target); auto xy = instance->check(); *x = xy.first; *y = xy.second; } extern "C" __declspec(dllexport) void destroy_instrument(void* ins) { GCHandle handle = GCHandle::FromIntPtr(IntPtr(ins)); handle.Free(); } - 编译得到dll、lib文件后,Qt项目不管是Qt Creator还是VS的都可以直接作为原生C库链接调用,完全不需要开启CLR支持,和调用普通第三方库没有区别。
常见问题说明
- Qt Creator本身不支持C++/CLI的编译和调试,如果要在Qt Creator里开发,只能用上述方案2,把CLR部分作为独立DLL调用。
- 不要给Qt相关的代码文件开启CLR支持,只要隔离了CLR代码到单独的文件,Qt的功能完全不会受影响。
- 跨平台适配的时候,只需要把Windows平台下调用这个CLR DLL的逻辑做个平台判断,非Windows平台用其他对应实现即可,不影响整体代码的移植性。
内容的提问来源于stack exchange,提问作者Bart M
相关产品推荐
相关产品推荐

