【问题标题】:wraping a native library that implements a callback in c#包装在 C# 中实现回调的本机库
【发布时间】:2012-04-04 04:47:12
【问题描述】:

我有一个 Visual Studio 2008 C# .NET 3.5 类,它提供对本机库的访问。该库有一个 Register 方法,允许用户指定将在某些事件上激活的回调。我在下面提供了一个 C# 实现:

internal class MyLibHandle : SafeHandleZeroOrMinusOneIsInvalid { /*...*/ }

internal static class NativeMethods
{
    public delegate void OnSomeEventDelegate (FOO foo, IntPtr user);

    [DllImport("MyLib.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.U1)]
    public static extern bool MyLib_Register(MyLibHandle handle, OnSomeEventDelegate callback, IntPtr user);
}

public class MyWrappedLib : IDisposable
{
    private MyLibHandle handle_;

    private event EventHandler<OnSomeEventArgs> some_event_int_;

    public event EventHandler<OnSomeEventArgs> SomeEvent
    {
        add
        {
            if (some_event_int_ == null)
            {
                if (!NativeMethods.MyLib_Register(handle_, ReceivedSomeEvent, IntPtr.Zero))
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            some_event_int_ += value;
        }
        remove
        {
            some_event_int_ -= value;
            if (some_event_int_ == null)
            {
                if (!NativeMethods.MyLib_DeRegister(handle_, -1))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
    }

    private void ReceivedSomeEvent(FOO foo, IntPtr user)
    {
        OnSomeEvent(new OnSomeEventArgs() { foo = foo });
    }

    protected virtual void OnBeacon(OnSomeEventArgs args)
    {
        EventHandler<OnSomeEventArgs> evt = some_event_int_;
        if (evt != null)
            evt(this, args);
    }
}

这可行,但我收到了一些不祥的警告

warning : CA1065 : Microsoft.Design : 'MyWrappedLib.SomeEvent.add(EventHandler<OnSomeEventArgs>)' creates an exception of type 'Win32Exception', an exception type that should not be raised in this type of method.

warning : CA2122 : Microsoft.Security : 'MyWrappedLib.SomeEvent.add(EventHandler<OnSomeEventArgs>)' calls into 'Marshal.GetLastWin32Error()' which has a LinkDemand. By making this call, 'Marshal.GetLastWin32Error()' is indirectly exposed to user code.

处理这种情况的推荐方法是什么?我应该创建一个方法来处理事件订阅而不是传统的添加吗?消除;访问器?

谢谢

【问题讨论】:

    标签: c# events delegates callback


    【解决方案1】:

    对于事件访问器,允许以下异常类型:

    • System.InvalidOperationException 和所有派生类(包括 System.ObjectDisposedException)

    • System.NotSupportedException 和所有派生词

    • ArgumentException 及其派生词

    为什么原生方法会返回 false? 会不会跟一些外在的条件有关, 还是传递的参数无效?

    所以我会将 Win32Exception 包装为 InvalidOperationException 的内部, 或 ArgumentException,具体取决于您的情况。

    第二个警告 (CA2122) 是关于安全性的 - 它警告 Marshal.GetLastWin32Error 执行安全检查, 而你的代码没有。此安全检查仅执行一次, 在第一次通话。之后的所有调用都未验证访问权限, 出于性能原因。所以理论上,第一次调用可以由 受信任的用户,并且所有进一步的调用都不会受到限制。

    您需要使用以下属性装饰您的事件处理程序:

    [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]

    (它将检查代码是否有权调用托管代码) 如果您的应用程序不关心安全性,则取消此警告。

    this question详细解释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-08
      • 1970-01-01
      • 2017-04-13
      • 2014-08-29
      • 1970-01-01
      • 2014-08-26
      • 1970-01-01
      相关资源
      最近更新 更多