Вопрос

Я создаю ветку, которая ищет окно. Когда он находит окно, он переопределяет свой WindowProc и обрабатывает wm_command и wm_close.

Вот код, который ищет окно и подклассет его:

public void DetectFileDialogProc()
{
   Window fileDialog = null;
   // try to find the dialog twice, with a delay of 500 ms each time
   for (int attempts = 0; fileDialog == null && attempts < 2; attempts++)
   {
      // FindDialogs enumerates all windows of class #32770 via an EnumWindowProc
      foreach (Window wnd in FindDialogs(500))
      {            
         IntPtr parent = NativeMethods.User32.GetParent(wnd.Handle);
         if (parent != IntPtr.Zero)
         {
            // we're looking for a dialog whose parent is a dialog as well
            Window parentWindow = new Window(parent);
            if (parentWindow.ClassName == NativeMethods.SystemWindowClasses.Dialog)
            {
               fileDialog = wnd;
               break;
            }
         }
      }
   }
   // if we found the dialog
   if (fileDialog != null)
   {
      OldWinProc = NativeMethods.User32.GetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC);
      NativeMethods.User32.SetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WindowProc(WndProc)).ToInt32());
   }
}

И Windowproc:

public IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
   lock (this)
   {
      if (!handled)
      {
         if (msg == NativeMethods.WM_COMMAND || msg == NativeMethods.WM_CLOSE)
         {       
            // adding to a list. i never access the window via the hwnd from this list, i just treat it as a number
            _addDescriptor(hWnd);
            handled = true;
         }
      }
   }
   return NativeMethods.User32.CallWindowProc(OldWinProc, hWnd, msg, wParam, lParam);
}        

Все это хорошо работает в нормальных условиях. Но я вижу два случая плохого поведения в порядке плохого:

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

  2. Если я немедленно закрою диалог с помощью кнопки «X» (WM_CLOSE), приложение срабатывает. Я считаю, что это сбои в WindowProc, но я не могу получить там точку останова. Я получаю AccessViolationException, исключение говорит: «Попытка прочитать или написать защищенную память. Это часто указывает на то, что другая память повреждена». Это состояние гонки, но то, чего я не знаю. К вашему сведению, я сбрасывал старый WindowProc, как только обработал команды, но это рухнуло еще чаще!

Есть идеи о том, как я могу решить эти проблемы?

Это было полезно?

Решение 2

Наконец -то придумал решение, атакуя проблему под другим углом. Я смог установить общеобразовательный крюк в управляемом коде, используя SetwineVenthook, и опцию winevent_outofcontext, который удивительно имеет свойство: функция обратного вызова не отображается в адресное пространство процесса, который генерирует событие. Я затрагиваю событие события_SYSTEM_DIALOGSTART для получения уведомлений всякий раз, когда создается диалог, и Event_system_dialoGend при его уничтожении.

Другие советы

Две точки наблюдения, которые я могу сделать ....

  • В твоей DetectFileDialogProc, вы сравниваете wnd Чтобы нулевой, это IntPtr Тип Да? Если так, то эта проверка для сравнения должна быть if (wnd > IntPtr.Zero){ .... }
  • В твоей WndProc, вы используете this переменная для lock что плохо сделать ... ты должен сделать что -то подобное private readonly object objLock = new object(); и внутри вашего WndProc использовать это lock (objLock){....}

и посмотрите, решает ли это проблему ....

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top