提问人:Ralms 提问时间:11/7/2023 最后编辑:Ralms 更新时间:11/9/2023 访问量:60
调用 C++ DLL,仅从 C 导出__declspec#
Call C++ DLL with only __declspec exports from C#
问:
我正在向已讨论的主题提交一个新问题,因为我找不到解决方案或与我完全相同的场景。
我正在创建一个 .NET 8 解决方案,并尝试从 .DLL 调用 C++ 函数。
这个 DLL 它不是我的,我也没有 .lib、.obj 或 .pdb 文件。
有问题的 DLL 是 RakNet 的旧版本,因此我可以使用 GitHub 中最新的可用代码作为参考,但是,这个 DLL 是旧版本,所以我不能从 GitHub 再次构建它。
想要专门使用此.DLL的主要原因是因为我正在为游戏开发一个“兼容”的自定义服务器,因此客户端也将使用这个旧版本的RakNet。
我已经通过使用 Cutter 或 Ghidra 进行反编译来验证,导出的函数仍然与 GitHub 代码中的函数相同。
这些函数以正常__declspec导出,而不是作为“extern ”C“导出,因此,在使用 [DLLImport()] 注释时,C# 似乎无法加载它并找到函数。
我尝试使用 VS Tools 创建 .lib 文件,但它不起作用。
在花了 5 个多小时解决这个问题之后,我决定寻求帮助并检查是否有人处理过类似的情况,并知道是否可能以及如何从具有这些限制的 C# 调用 C++ DLL。 真的在寻找任何提示或想法。
谢谢。
编辑1:
添加当前问题和错误的更具体上下文。
为了分离DLL位置并能够具体化,我加载了它:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(string dllToLoad);
public static void LoadRakNetDll()
{
var handle = LoadLibrary(dllPath);
if (handle == IntPtr.Zero)
{
Console.WriteLine("FAiled to load DLL");
}
}
然后,我尝试与之互操作的相关方法声明如下:
[DllImport("RakNet64", CallingConvention = CallingConvention.StdCall)]
public static extern int Startup(uint maxConnections, SocketDescriptor socketDescriptors, uint socketDescriptorCount, int threadPriority);
我已经测试了定义 EntryPoint,但是从异常中我可以看到省略它,.NET 将使用方法名称作为入口点。
我得到的例外是:
System.EntryPointNotFoundException
HResult=0x80131523
Message=Unable to find an entry point named 'Startup' in DLL 'RakNet64'.
我还测试了更改 CallingConvention,但没有区别。
从做研究、询问 AI 等,到处都指出 DLL 需要使用“extern”C“导出函数,但我可能是错的。
编辑2:
在查看 RakNet 文件时,“3.x_to_4x_upgrade.txt”让我感到好奇,检查后,从 v3 到 v4 的第一个重大变化是 RakPeer::Connect() 返回一个枚举,我知道我正在为服务器做游戏的 RakNet DLL 也有,通过反编译确认。 这让我相信它们实际上是同一个版本。 在此之后,我根据 GitHub 中的代码构建了 RakNet,创建了 SWIG 包装器,一切正常。
答: 暂无答案
评论
DllImport
将正常工作,但您可能必须使用其字段来指定正确的导出名称,因为它们将被 C++ 在没有 .EntryPoint
extern "C"