Frage

Ich erstelle einen Thread, der nach einem Fenster sucht. Wenn es das Fenster findet, überschreibt es das Fensterproc und behandelt Wm_Command und Wm_Close.

Hier ist der Code, der nach dem Fenster sucht und es unterklebt:

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());
   }
}

Und das Fensterproc:

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);
}        

Dies alles funktioniert unter normalen Bedingungen gut. Aber ich sehe zwei Fälle von schlechter Verhalten in der Reihenfolge der Schlechtigkeit:

  1. Wenn ich den Dialog nicht innerhalb einer Minute schließe, stürzt die App ab. Liegt das daran, dass der Faden Müll erfasst wird? Dies würde einen Sinn ergeben, was GC angeht, was den Thread erledigt hat? Wenn dies der Fall ist (und ich weiß nicht, dass dies der Fall ist), wie kann ich den Thread so lange bleiben, solange der Dialog in der Nähe ist?

  2. Wenn ich den Dialog mit der Schaltfläche 'x' sofort schließe (WM_CLOSE), stürzt die App ab. Ich glaube, es stürzt im Fensterproc zusammen, aber ich kann dort keinen Haltepunkt bekommen. Ich erhalte eine AccessViolationException, in der Ausnahme "Versuch, geschütztes Gedächtnis zu lesen oder zu schreiben. Dies ist oft ein Hinweis darauf, dass ein anderer Gedächtnis beschädigt ist." Es ist eine Rennbedingung, aber von dem, was ich nicht weiß. Zu Ihrer Information, ich hatte das alte Fensterproc zurückgesetzt, als ich die Befehle verarbeitet habe, aber das stürzte noch öfter ab!

Irgendwelche Ideen, wie ich diese Probleme lösen kann?

War es hilfreich?

Lösung 2

Kam schließlich auf eine Lösung und griff das Problem aus einem anderen Blickwinkel an. Ich konnte einen systemweiten Haken im verwalteten Code mit SetWineventHook und der Option Winevent_outofContext festlegen, die erstaunlich über die Eigenschaft verfügt: Die Rückruffunktion wird nicht in den Adressraum des Prozesses zugeordnet, der das Ereignis generiert. Ich fege das Event Event_System_Dialogstart, um Benachrichtigungen zu erhalten, wenn ein Dialog erstellt wird, und Event_System_Dialogend, wenn es zerstört wird.

Andere Tipps

Zwei Beobachtungspunkte, die ich machen kann ....

  • In deiner DetectFileDialogProc, Sie vergleichen wnd zu null, das ist ein IntPtr Tippen Sie ja? Wenn ja, sollte dieser Scheck über den Vergleich sein if (wnd > IntPtr.Zero){ .... }
  • In deiner WndProc, Sie verwenden die this Variable für die lock Welches ist eine schlechte Sache ... Sie sollten so etwas tun private readonly object objLock = new object(); und in deinem WndProc benutze das lock (objLock){....}

und prüfen Sie, ob dies das Problem behebt ....

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top