我正在创建一个寻找窗口的线程。当它找到窗口时,它会覆盖其窗口,并处理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中崩溃了,但是我无法在那里得到断点。我得到了访问violationException,例外说:“试图读取或写下受保护的内存。这通常表明其他记忆是损坏的。”它是种族条件,但我不知道。仅供参考,一旦我处理了命令,我就已经重置了旧的窗口,但是那崩溃的频率更高!

关于我如何解决这些问题的任何想法?

有帮助吗?

解决方案 2

最终提出了一个解决方案,从不同角度攻击了问题。我能够使用setWineVenthook在托管代码中设置一个系统范围的挂钩,而winevent_outofcontext的选项具有惊人的属性:回调函数未映射到生成事件的过程的地址空间中。我将Event_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