我已经获得了一个外部c ++ dll,我需要在我的C#项目中加载和使用它。 dll附带一个头文件,这是(简化/匿名):
typedef struct
{
int (*GetVersion)();
int (*StartServer)(const char *ip, int port);
void (*OnRemoteError)(void *caller, int error);
} RemoteServerPluginI;
extern "C" __declspec(dllexport) RemoteServerPluginI* GetServerPluginInterface();
关于如何在我的C#项目中使用它,我有几个问题:
非常感谢任何相关文档的链接。
答案 0 :(得分:0)
BIG DISCLAIMER :此时我无法与实际系统接口,因此这可能是错误的。但是我已经成功加载了dll并阅读了版本,这让我觉得我可能已经解决了它。如果有任何问题,我会更新答案。
首先要声明struct
将C ++ struct
映射到我们的C#代码中。
我们可以使用MarshalAs
属性告诉编组人员这些委托实际上只是函数指针:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int GetVersionT();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int StartServerT(string ip, int port);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnRemoteErrorT(object caller, int error);
public struct RemoteServerPluginI
{
[MarshalAs(UnmanagedType.FunctionPtr)] public GetVersionT GetVersion;
[MarshalAs(UnmanagedType.FunctionPtr)] public StartServerT StartServer;
[MarshalAs(UnmanagedType.FunctionPtr)] public OnRemoteErrorT OnRemoteError;
// a lot of other methods not shown
}
然后我们创建一个帮助器类,使用DLLImport加载DLL并调用dll中定义的方法。
使用extern方法可以轻松完成:
[DllImport("data/remoteplugin.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetServerPluginInterface();
请注意,我们必须指定调用约定。
另一个需要注意的重要事项是:此方法返回IntPtr
个对象。
幸运的是我们现在已经完成了,我们只需要将其转换为正确的类型:
var ptr = GetServerPluginInterface();
var server = (RemoteServerPluginI)Marshal.PtrToStructure(ptr, typeof(RemoteServerPluginI));
此时我只是将所有内容都包含在便利类中以管理访问权限,并且瞧! 这是最终的代码:
public static class IntPtrExtensions
{
// I'm lazy
public static T ToStruct<T>(this IntPtr ptr)
=> (T)Marshal.PtrToStructure(ptr, typeof(T));
}
public static class RemoteControlPlugin
{
[DllImport("path/to/remoteplugin.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetServerPluginInterface();
private static RemoteServerPluginI? _instance = null;
public static RemoteServerPluginI Instance =>
(RemoteServerPluginI)(
_instance ??
(_instance = GetServerPluginInterface().ToStruct<RemoteServerPluginI>())
);
}
internal static class Program
{
private static void Main(string[] args)
{
var remoteServer = RemoteControlPlugin.Instance;
Console.WriteLine(remoteServer.GetVersion()); // Easy!
}
}