目前我正在尝试使用DLL导入在C#下使用C ++库。图书馆被称为拦截。 问题是我不知道如何翻译头文件的#define条目和typedef声明:
https://github.com/oblitum/Interception/blob/master/include/interception.h
我尝试使用“using”指令,但没有成功(我无法访问void定义)。 而且,我没有理解__declspec(dllimport)在这个标题中的作用。在我的c#项目中,我只是忽略了它?这样做好吗?
这是我想在c#中使用的代码(它是库的一个示例)
https://github.com/oblitum/Interception/blob/master/samples/hardwareid/main.cpp
编辑:
我尝试了什么:基本输入:
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
void interception_set_filter(void* context, InterceptionPredicate predicate, ushort filter);
我不知道如何转换InterceptionPredicate。根据头文件,InterceptionFilter是一个ushort,而InterceptionContext是一个void指针(void *)。
答案 0 :(得分:2)
C ++库应该编译为.DLL文件。此.DLL文件应具有导出的函数。您可以使用Depends工具检查从.DLL导出的内容。 .NET代码可以使用所谓的“平台调用”来调用C ++导出的函数。
现在,我强烈建议您深入了解一下将引导您的Platform Invoke Tutorial。
PS:void *
应该在c#中声明为IntPtr。 enums
应重新声明为枚举。函数应声明为标有DllImport
属性的静态extern方法。
答案 1 :(得分:1)
首先,看起来你正在尝试实现一个全局键盘/鼠标钩子......如果是这种情况,我建议谷歌搜索'C#低级键盘和鼠标钩'。
现在提出您的问题,首先是__declspec(dllimport)
问题:如果您实际使用的是C ++应用程序中的标头,那么C#DllImport
的C ++等效项就是这样的。所以在效果你没有忽略它,你实现了它。在C ++中,它只是告诉链接器声明为这样的函数将从特定的DLL导入,而不是它是一个本地函数(非常类似于C#DllImport
指令所做的)
接下来是函数指针问题(InterceptionPredicate)。在标题中,它被定义为:
typedef int (*InterceptionPredicate)(InterceptionDevice device);
InterceptionDevice
只是一个'int'。因此InterceptionPredicate只是一个函数指针类型(或C#中的Delegate),因此InterceptionPredicate的委托定义如下所示:
// [UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate int InterceptionPredicate (int device);
关于UnmanagedFunctionPointer调用约定描述符的注释:如果你知道导出的函数可能正在使用什么类型的调用约定(stdcall,fastcall,cdecl),你可以在这里指定,以便.NET封送程序知道如何传递托管/非托管代码之间的数据,但如果您不知道它或通常没有指定,您可以将其关闭。
此外,正如其他人所提到的,除非您在C#属性中指定了“不安全”标记,否则{C}属性中void*
类型应始终为IntPtr
。
另外,请务必将C#代码中的dll函数标记为public static extern
,请参阅下面的示例。
所以为了举例说明你已经指定的功能,这里可以做些什么:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InterceptorTest
{
public class Interceptor : IDisposable
{
#region DllImports
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr interception_create_context();
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void interception_destroy_context(IntPtr context);
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void interception_set_filter(IntPtr context, InterceptionPredicate predicate, ushort filter);
// The function pointer type as defined in interception.h that needs to be defined as a delegate here
public delegate int InterceptionPredicate(int device);
#endregion
#region private members
private InterceptionPredicate m_PredicateDelegate { get; set; }
private IntPtr m_Context { get; set; }
#endregion
#region methods
public Interceptor(ushort filter)
{
// be sure to initialize the context
this.m_PredicateDelegate = new InterceptionPredicate(this.DoSomethingWithInterceptionPredicate);
this.m_Context = interception_create_context();
interception_set_filter(this.m_Context, this.m_PredicateDelegate, filter);
}
private void Cleanup()
{
interception_destroy_context(this.m_Context);
// the next line is not really needed but since we are dealing with
// managed to unmanaged code it's typically best to set to 0
this.m_Context = IntPtr.Zero;
}
public void Dispose()
{
this.Cleanup();
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing) { this.Cleanup(); }
}
public int DoSomethingWithInterceptionPredicate(int device)
{
// this function is something you would define that would do something with
// the device code (or whatever other paramaters your 'DllImport' function might have
// and return whatever interception_set_filter is expecting
return device;
}
#endregion
}
static class Program
{
[STAThread]
private static void Main(string[] argv)
{
Interceptor icp = new Interceptor(10);
// do something with the Interceptor object
}
}
}
希望能让你走上正轨。
答案 2 :(得分:0)