проблема с делегатом - PullRequest
       15

проблема с делегатом

2 голосов
/ 17 февраля 2010

Я сделал это для вызова неуправляемой функции из кода Си. pCallback - это указатель на функцию, поэтому на управляемой стороне находится делегат.

[DllImport("MyDLL.dll")]

public static extern Result SetCallback(
            IntPtr handle,
            Delegate pCallback,
            CallbackType Type);

Сейчас я настраиваю

    public delegate void pfnCallback(uint PromptID, ttsEventType evt, IntPtr lData);

    public Form1()
    {
        pfnCallback cb = new pfnCallback(cback);
        (...)
        Wrapper.SetCallback(handle, cb, IntPtr.Zero, CallBackType.DEFAULT);
        (...)
        }

Это дает мне сообщение об ошибке "... при передаче делегатов в неуправляемый код они должны оставаться в живых ..."

Кто-нибудь может мне помочь?

Привет

Ответы [ 4 ]

3 голосов
/ 17 февраля 2010

Я считаю, что вам нужно расширить область действия cb, чтобы эта переменная продолжала существовать, и обращаться к функции обратного вызова до тех пор, пока неуправляемый код может захотеть вызвать ее. Неуправляемый код не участвует в отслеживании ссылок .NET, поэтому, если вы не принудительно сохраните ссылку на обратный вызов в коде .NET, он будет освобожден платформой, и неуправляемый код не сможет правильно вызвать его после что.

3 голосов
/ 17 февраля 2010

Насколько я понимаю сообщение, вы должны сделать это так:

public delegate void pfnCallback(uint PromptID, ttsEventType evt, IntPtr lData);

public pfnCallback cb = new pfnCallback(cback);

public Form1()
{
    (...)
    Wrapper.SetCallback(handle, cb, IntPtr.Zero, CallBackType.DEFAULT);
    (...)
}
2 голосов
/ 17 февраля 2010

Вы путаете объявление типа делегата с экземпляром делегата. Да, вы сделали публичное заявление своего делегата, это было неправильно. Только класс Form1 использует его, он должен быть закрытым. Здесь важен экземпляр делегата, созданный вами с новым оператором.

Прямо сейчас вы храните экземпляр в локальной переменной конструктора Form1. Это сохраняет ссылку на экземпляр в течение нескольких микросекунд. Как только конструктор завершает работу, эта ссылка исчезает, и сборщик мусора может собирать экземпляр делегата в любой момент после этого. Он не может видеть, что неуправляемый код сохраняет ссылку на него, сборщик может обнаруживать только ссылки, содержащиеся в управляемом коде.

Ничего хорошего не происходит, когда неуправляемый код вызывает обратный вызов в собранном экземпляре делегата, вы услышите громкий звук kaboom. Вы должны изменить свой код, чтобы была управляемая ссылка на экземпляр. Один из простых способов сделать это - добавить закрытый член в класс Form1 для хранения экземпляра.

Даже если это может быть недостаточно хорошо, объект Form1 также будет собирать мусор в будущем. Который также собирает объект делегата. Вы также должны убедиться, что неуправляемый код не может использовать обратный вызов после того, как это произойдет. Учитывая имя класса (Form1), это вряд ли произойдет в этом конкретном случае. Но защитите код и сделайте вызов, который сбрасывает обратный вызов в обработчике событий FormClosing формы.

0 голосов
/ 17 февраля 2010

Попробуйте переменную обратного вызова cb глобально

...