обёртывание нативной библиотеки, которая реализует обратный вызов в c # - PullRequest
3 голосов
/ 19 марта 2012

У меня есть класс 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.

Каков рекомендуемый способ решения этой ситуации?Должен ли я создать метод для обработки подписок на события вместо традиционного добавления;Удалить;аксессоры?

Спасибо

1 Ответ

1 голос
/ 30 марта 2013

Для средств доступа к событиям допускаются следующие типы исключений:

  • System.InvalidOperationException и все производные (включая System.ObjectDisposedException )

  • System.NotSupportedException и все производные

  • ArgumentException и производные

Почему нативный метод возвращает false? Будет ли это связано с какими-то внешними условиями, или это результат передачи неверных параметров?

Так что я бы обернул Win32Exception как внутренний для InvalidOperationException, или ArgumentException, в зависимости от вашей ситуации.

Второе предупреждение (CA2122) о безопасности - он предупреждает, что Marshal.GetLastWin32Error выполняет проверки безопасности, а твой код нет. Эта проверка безопасности выполняется только один раз, по первому звонку. Все звонки после этого не проверяются на права доступа, по причинам производительности. Таким образом, в теории, первый звонок может быть сделан доверенный пользователь, и все дальнейшие звонки не будут ограничены.

Вам нужно украсить ваш обработчик событий следующим атрибутом:

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

(он проверит, есть ли у кода права на вызов управляемого кода) или отключите это предупреждение, если безопасность вашего приложения не имеет значения.

Подробности очень подробно объясняются в этом вопросе .

...