Как работают делегаты и обратный вызов? - PullRequest
0 голосов
/ 17 декабря 2011

Я не совсем понимаю эти темы.

Я работаю с несколькими методами WinAPI

public delegate bool Win32Callback(IntPtr hwnd, ref IntPtr lParam);

[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

и

public static bool BrowserEnumChildrenCallback(IntPtr hWnd, ref IntPtr lParam)
{
    if (hWndMeetsConditions)
        return true;
    //code
    return false;
}

Возможно ли получить hWndдля которого было возвращено true от BrowserEnumChildrenCallback?

Win32Callback callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
if (EnumChildWindows(hWnd, callBack, hWnd))
{
    //here
}

Ответы [ 2 ]

3 голосов
/ 17 декабря 2011

Несколько проблем:

  • Объявление делегата неверно, последний аргумент - IntPtr, а не ref IntPtr .
  • Обратный вызов должен возвращать true для продолжения итерации, вы делаете это в обратном направлении
  • Записать GC.KeepAlive (callBack) после вызова EnumChildWindows (), чтобы предотвратить сборку мусора объектом делегата.
  • Не используйте возвращаемое значение EnumChildWindows (), документы SDK отмечают, что оно не используется. Вы обнаружите ошибку, не найдя окно.

Отвечая на актуальный вопрос: сохраните дескриптор окна в поле вашего класса. Таким образом:

private IntPtr windowFound;

private void iterateChildWindows(IntPtr parent) {
    windowFound = IntPtr.Zero;
    var callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);
    EnumChildWindows(parent, callBack, IntPtr.Zero);
    GC.KeepAlive(callBack);
    if (windowFound != IntPtr.Zero) {
       // etc..
    }
}

private bool BrowserEnumChildrenCallback(IntPtr hWnd, IntPtr lParam)
{
    if (hWndMeetsConditions(hWnd)) {
        windowFound = hWnd;
        return false;
    }
    return true;
}

Лямбда тоже хорошо работает.

1 голос
/ 17 декабря 2011
List<IntPtr> _hwnds = new List<IntPtr>();
public static bool BrowserEnumChildrenCallback(IntPtr hWnd, ref IntPtr lParam) 
{     
     if (hWndMeetsConditions)         
     {
          _hwnds.Add( hWnd );
          return true;     
     }

     //code     
     return false; 
} 

Win32Callback callBack = new MainWindow.Win32Callback(BrowserEnumChildrenCallback);  
if (EnumChildWindows(hWnd, callBack, hWnd))  
{      
    // here  
    // you have it in _hwnd
}  
...