如何从C#项目生成供C++调用的.lib与.dll文件?
问题描述
我想在C++代码中调用C#生成的DNL.dll和DNL_MATLAB.dll中的所有方法与参数,但目前因缺少.lib文件无法实现——单独使用.dll似乎行不通。我已获取生成这些.dll的完整C#项目,它通过scriptcs和mono编译,在Windows10的Cygwin窗口中运行Makefile可成功生成目标.dll,但始终不会生成.lib文件。我尝试用dumpbin从.dll生成.lib但完全失败,以下是生成.dll的Makefile及部分C#代码,恳请帮助解决。
附:生成DLL的Makefile
.PHONY: clean generate ./bin/Release/DNL.dll all: clean generate ./bin/Release/DBL.dll ./bin/Release/DNL_MATLAB.dll generate: @cd doc; doxygen Doxyfile_DNL @rm -rf ./bin/data/xml @cd data && doxygen val_NET_doxygen_conf @mkdir -p ./var @rm -rf ./var/* scriptcs ./build/scripts/GenerateAPI.csx -- release/v5.1.0/ Release 0 val Single ./bin/bin/Release/DNL.dll: mkdir -p ./bin/Release mkdir -p ./src/Source_GENERAL @rm -f ./src/Source_GENERAL/*.cs @cp -f ./src/auto*.cs ./src/Source_GENERAL @cp -f ./src/Api.cs ./src/Source_GENERAL @cp -f ./src/ErrorCodes.cs ./src/Source_GENERAL @cp -f ./src/Host.cs ./src/Source_GENERAL @cp -f ./src/IController.cs ./src/Source_GENERAL @cp -f ./src/Logger.cs ./src/Source_GENERAL @cp -f ./src/HelperFunctions.cs ./src/Source_GENERAL @cp -f ./src/Spi.cs ./src/Source_GENERAL @cp -f ./src/UUTBase.cs ./src/Source_GENERAL mcs ./src/Source_GENERAL/*.cs ./src/Controllers/*.cs -t:library -out:./bin/Release/DNL.dll -r:System.Net.Http -sdk:4.6.1 @rm -f ./src/Source_GENERAL/* @rm -r ./src/Source_GENERAL ./bin/Release/DNL_MATLABl.dll: mkdir -p ./bin/Release mkdir -p ./src/Source_MATLAB @rm -f ./src/Source_MATLAB/*.cs @cp -f ./src/mat*.cs ./src/Source_MATLAB @cp -f ./src/Api.cs ./src/Source_MATLAB @cp -f ./src/ErrorCodes.cs ./src/Source_MATLAB @cp -f ./src/Host.cs ./src/Source_MATLAB @cp -f ./src/IController.cs ./src/Source_MATLAB @cp -f ./src/Logger.cs ./src/Source_MATLAB @cp -f ./src/Spi.cs ./src/Source_MATLAB @cp -f ./src/HelperFunctions.cs ./src/Source_MATLAB @cp -f ./src/UUTBase.cs ./src/Source_MATLAB mcs ./src/Source_MATLAB/*.cs ./src/Controllers/*.cs -t:library -out:./bin/Release/DNL_MATLAB.dll -r:System.Net.Http -sdk:4.6.1 @rm -f ./src/Source_MATLAB/*.cs @rm -r ./src/Source_MATLAB ./bin/Debug/DNL.dll: mkdir -p ./bin/Release @cp -f ./src/*.cs ./src/Source_GENERAL $(CC) ./src/Source_GENERAL/*.cs ./src/Controllers/*.cs -t:library -debug -out:$(BINDIR)/$(CONFIG)/ DNL.dll -r:System.Net.Http -sdk:4.6.1 @rm -f ./src/Source_GENERAL/*.cs ./bin/Debug/DNL_MATLAB.dll: mkdir -p ./bin/Release @cp -f ./src/*.cs ./src/Source_MATLAB mcs ./src/Source_MATLAB/*.cs ./src/Controllers/*.cs -t:library -debug -out:./bin/Release/DNL_MATLAB.dll -r:System.Net.Http -sdk:4.6.1 @rm -f ./src/Source_MATLAB/*.cs clean: @rm -rf doc/out/html @rm -rf doc/out/latex @rm -f ./src/auto* @rm -f ./src/mat* #@rm -rf ./bin/* @rm -rf ./src/Source_MATLAB @rm -rf ./src/Source_GENERAL run: build @mono ./bin/app.exe test: ./bin/Release/DNL.dll @rm -rf ./bin/Release/logs python3 ./test/python_test.py ./bin/Release/DNL.dll hwtest: ./bin/Release/DNL.dll @rm -rf ./bin/Release/logs python3 ./test/python_hw_test.py ./bin/Release/DNL.dll
附:部分C#代码片段
using System; using System.Collections.Generic; namespace DNL { public class _ADC12 : _module { static internal UInt32 myModuleAddress = 0x7; public class _PON : _register { static internal UInt32 myAddress = (myModuleAddress << 12) | 0x0; public _PON(_UUTBase _owner) : base(_owner, myAddress) {} public _spi F_PonLaunch {get => _owner.SpiProvider(myAddress, "PonLaunch");} public _spi F_Reserved0 {get => _owner.SpiProvider(myAddress, "Reserved0");} } public _PON R_PON { get { return new _PON(_owner); } } public class _CALIBRATION_STATUS : _register { static internal UInt32 myAddress = (myModuleAddress << 12) | 0x4; public _CALIBRATION_STATUS(_UUTBase _owner) : base(_owner, myAddress) {} public _spi F_CalibrationBusy {get => _owner.SpiProvider(myAddress, "CalibrationBusy");} public _spi F_CalibrationLaunchedOkay {get => _owner.SpiProvider(myAddress, "CalibrationLaunchedOkay");} public _spi F_Reserved0 {get => _owner.SpiProvider(myAddress, "Reserved0");} } }
解决方案
首先要明确:你生成的是**.NET托管DLL**,不是原生C++的DLL,这类DLL没有原生DLL的导出表结构,所以不会自动生成.lib,dumpbin也无法从它生成可用的.lib。下面是几种可行的调用方案:
方案一:用C++/CLI做中间层
这是最通用的解决方案,适合调用整个C#类库的所有功能:
- 创建C++/CLI类库项目,添加对
DNL.dll的引用 - 编写托管包装类,将C#中的类、方法、属性封装成原生C能识别的接口(比如用
public ref class包装,暴露原生C可调用的函数) - 编译这个C++/CLI项目,会生成原生DLL和对应的
.lib文件 - 在你的原生C++项目中引用这个
.lib和DLL,直接调用包装好的接口
方案二:给C#方法添加导出标记(P/Invoke)
如果只需要调用特定方法,可以给C#方法添加导出特性,让DLL生成原生导出表:
- 在C#项目中安装
UnmanagedExportsNuGet包 - 给需要导出的C#方法添加
[DllExport]特性,指定导出名称和调用约定 - 修改Makefile中的
mcs编译命令,确保引用UnmanagedExports相关的程序集 - 重新编译生成DLL后,用
dumpbin /exports DNL.dll能看到导出的函数,此时可以用lib /def:DNL.def /out:DNL.lib生成.lib文件,然后在C++中用__declspec(dllimport)声明这些方法直接调用
方案三:使用COM互操作
将C#类库注册为COM组件,通过COM接口调用:
- 在C#类上添加
[ComVisible(true)]特性,确保类和方法对COM可见 - 用
regasm.exe工具注册DNL.dll(比如regasm /codebase DNL.dll) - 用
tlbexp.exe生成类型库文件(.tlb) - 在C++项目中导入这个
.tlb文件,通过COM对象的接口调用C#方法
内容的提问来源于stack exchange,提问作者zeitoun
相关产品推荐
相关产品推荐

