导入:在C#下使用C ++库的语法转换

时间:2012-10-29 16:35:06

标签: c# c++ dll

目前我正在尝试使用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 *)。

3 个答案:

答案 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)

好的,我发现了一个隐藏在GIT上的示例代码。谢谢谷歌!

https://gist.github.com/1959219

它通过一个工作示例来准备DLL输入的所有功能。