Поделиться через


Как реализовать функции обратного вызова

В следующей процедуре и примере показано, как управляемое приложение с помощью вызова платформы может распечатать значение дескриптора для каждого окна на локальном компьютере. В частности, процедура и пример используют функцию EnumWindows для перебора поэтапно списка окон и управляемую функцию обратного вызова (с именем CallBack) для печати значения дескриптора окна.

Реализация функции обратного вызова

  1. Ознакомьтесь с сигнатурой для EnumWindows функции, прежде чем продолжить реализацию. EnumWindows имеет следующую подпись:

    BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
    

    Одним из подсказок, что для этой функции требуется обратный вызов, является наличие аргумента lpEnumFunc . Часто можно увидеть префикс lp (длинный указатель) в сочетании с суффиксом Func в именах аргументов, которые принимают указатель на функцию обратного вызова. Документация по функциям Win32 см. в пакете SDK для Платформы Майкрософт.

  2. Создайте управляемую функцию обратного вызова. В примере объявляется тип делегата CallBack, который принимает два аргумента (hwnd и lparam). Первый аргумент — это дескриптор окна; второй аргумент определяется самим приложением. В этом выпуске оба аргумента должны быть целыми числами.

    Функции обратного вызова обычно возвращают ненулевое значение, чтобы указать успешность и ноль, чтобы указать ошибку. Этот пример явно задает возвращаемое значение true, чтобы продолжить перечисление.

  3. Создайте делегат и передайте его как аргумент в функцию EnumWindows. Вызов платформы преобразует делегат в знакомый формат обратного вызова автоматически.

  4. Убедитесь, что сборщик мусора не удаляет делегат до того, как функция обратного вызова завершит свою работу. При передаче делегата в качестве параметра или передачи делегата, содержащегося в виде поля в структуре, он остается незаборным в течение длительности вызова. Таким образом, как показано в следующем примере перечисления, функция обратного вызова завершает свою работу до возврата вызова и не требует дополнительных действий управляемого вызывающего объекта.

    Однако если функция обратного вызова может вызываться после возврата вызова, управляемый вызывающий объект должен выполнить шаги, чтобы обеспечить, чтобы делегат не был завершен до завершения функции обратного вызова. Пример см. в примере GCHandle.

Example

Imports System
Imports System.Runtime.InteropServices

Public Delegate Function CallBack( _
hwnd As Integer, lParam As Integer) As Boolean

Public Class EnumReportApp

    Declare Function EnumWindows Lib "user32" ( _
       x As CallBack, y As Integer) As Integer

    Public Shared Sub Main()
        EnumWindows(AddressOf EnumReportApp.Report, 0)
    End Sub 'Main

    Public Shared Function Report(hwnd As Integer, lParam As Integer) _
    As Boolean
        Console.Write("Window handle is ")
        Console.WriteLine(hwnd)
        Return True
    End Function 'Report
End Class 'EnumReportApp
using System;
using System.Runtime.InteropServices;

public delegate bool CallBack(int hwnd, int lParam);

public class EnumReportApp
{
    [DllImport("user32")]
    public static extern int EnumWindows(CallBack x, int y);

    public static void Main()
    {
        CallBack myCallBack = new CallBack(EnumReportApp.Report);
        EnumWindows(myCallBack, 0);
    }

    public static bool Report(int hwnd, int lParam)
    {
        Console.Write("Window handle is ");
        Console.WriteLine(hwnd);
        return true;
    }
}
using namespace System;
using namespace System::Runtime::InteropServices;

// A delegate type.
delegate bool CallBack(int hwnd, int lParam);

// Managed type with the method to call.
ref class EnumReport
{
// Report the window handle.
public:
    [DllImport("user32")]
    static int EnumWindows(CallBack^ x, int y);

    static void Main()
    {
        EnumReport^ er = gcnew EnumReport;
        CallBack^ myCallBack = gcnew CallBack(&EnumReport::Report);
        EnumWindows(myCallBack, 0);
    }

    static bool Report(int hwnd, int lParam)
    {
       Console::Write(L"Window handle is ");
       Console::WriteLine(hwnd);
       return true;
    }
};

int main()
{
    EnumReport::Main();
}

См. также