NativeWindow-WnDProc



  • Hi ,

    ich habe mir eine Klasse abgeleitet von NativeWindow
    um auf bestimmte Nachrichten von Windows in der WndProc
    zu reagieren.
    Im NativeWindow habe ich ein Event deklariert bei den
    sich mein HauptFenster registriert.

    In der WndProc starte ich dann bei einen bestimmten Ereignissen das Event.
    Soweit so gut 😉

    Nun kann es sein, dass ein bestimmtes Ereignis in der Nachrichtenwarteschlange
    2-3 mal hintereinander eintritt. Normalerweise läuft die Wartschlange synchron ab, sprich hintereinander, doch in manchen Fällen ist mir aufgefallen, wenn ich in meinen Hauptfenster bei einen Fehler eine MessageBox ausgebe, wird der momentane Thread schlafen geschickt, bis der User auf OK klickt, wenn das passiert wird die WndProc wieder ausgeführt und unter Umständen mein event wieder gestartet, zwar mit neuen Parametern allerdings ist der andere Thread noch nicht beendet. Ich wollte nun mit einen LOCK verhindern, dass der 2 Thread irgendwelchen Blödsinn macht allerdings greift der LOCK nicht, die Funktion läuft einfach weiter. Wenn ich mir mal die THREADID und Namen ausgebe, sind die identisch. Hat da einer ne Idee an was das liegen kann?

    Gruß
    Nahasa

    public class IPCNativeWindow : NativeWindow
        {
          public event openFileEventHandler OpenMyFile;
          public IPCNativeWindow(string pID)
          {
            CreateParams cp = new CreateParams();
            cp.Caption = pID;
            CreateHandle(cp);
          }
    
          protected override void WndProc(ref Message m)
          {
            if (m.Msg == NativeMethods.WM_COPYDATA)
            {         
                NativeMethods.COPYDATASTRUCT data =
                  (NativeMethods.COPYDATASTRUCT)Marshal.
                  PtrToStructure(m.LParam, typeof(NativeMethods.COPYDATASTRUCT));
                string tArgs = null;
                if (data.cbData > 0 && data.lpData != IntPtr.Zero)
                {
    
                  byte[] buffer = new byte[data.cbData];
                  Marshal.Copy(data.lpData, buffer, 0, buffer.Length);
                  System.Text.UTF8Encoding enc2 = new System.Text.UTF8Encoding();
                  tArgs = enc2.GetString(buffer);
                  OpenMyFile(this, new OpenProjectFileArgs(tArgs));
                }          
            }
            else
              base.WndProc(ref m);
          }
        }
      }
    ...
    ...
    ...
    HauptFensterKlasse()
    {
    ...
    private Object mLockObject;
    
    public void openNewFile(string pFile)
    {
      lock (mLockObject)
      {
       if(LadeDatei())
         MessageBox("fehler"); //Thread schläft jetzt
       ...
      }
    }
    
    ...
    }
    


  • Hi,

    initialisierst du das mLockObject noch irgendwo?

    mfG
    KaPtainCugel



  • Hi KaPtainCugel,
    ja ich hatte versucht sie einmal
    als Static -Member für das Fenster zu deklarieren
    und einmal als normale Member im Konstruktor

    ...
    private static Object mLockObject = new Object();
    ...
    private Object mLockObject ;
    ...
    mLockObject = new Object();
    ....
    

    in beiden fällen greift das LOCK nicht,
    ich finde halt komisch das die Threads
    scheinbar auch die gleiche ManagedThreadId haben, dass hatte ich mir
    mal per Debug ausgegeben. Obwohl der eine Thread schläft weil der Dialog ja noch angezeigt wird und noch nicht mit OK bestätigt wurde.


  • Administrator

    Ich muss sagen, dass ich deiner Ablaufbeschreibung nicht ganz folgen kann. Kannst du es ein wenig genauer erläutern, wer wen wann aufruft? Was haben die beiden Codestücke miteinander zu tun?

    Grüssli



  • Hi Dravere,
    danke für die Antwort!
    Sorry du hast vollkommen recht, dass versteht keine Sau 😉

    ein Projekt sagt mehr als 1000 Worte 😃

    https://dl.dropboxusercontent.com/u/69535794/testApps.zip

    Ich habe mal ein Test -Projekt angelegt, mit dem man mein Problem gut simulieren kann.
    Wenn man das Projekt kompiliert, werden zwei Anwendungen erzeugt:
    testApp1 und testApp2

    Die TestApp1 eins besteht lediglich aus einen Button mit der man eine Nachricht an TestApp2 sendet. Die TestApp2 besteht aus einer ListView die dann die empfangenen Nachrichten anzeigt.

    Wenn man nun nur eine Instanz von testApp1 ausführt läuft noch alles so wie ich es mir vorgestellt habe testapp1 wartet, bis jemand in testapp2 auf ok klickt.

    Wenn ich nun 2 Instanzen von testApp1 starte und nach einander auf sendMessage klicke, in der jeweiligen Instanz, sieht man im debug Fenster
    sehr gut, dass die Reihenfolge nicht so ganz eingehalten wird, wie ich es im Prinzip benötige.

    Er müsste warten bis die Nachricht von der testapp1 Instanz1 fertig ist
    und dann erst die Nachricht weiter bearbeiten aus der zweiten Instanz.

    Der Lock-Befehl wird beim 2 Auruf einfach übergangen.

    Hoffe es ist jetzt ein bisschen verständlicher
    Gruß


  • Administrator

    Nett. Grundsätzlich hast du die Antwort bereits. Es ist der gleiche Thread, dadurch greift der Lock nicht. Es wäre auch nicht sehr gut, wenn dieser greifen würde, da du sonst einen Deadlock hättest.

    Du magst dich vielleicht nun fragen, wie es sein kann, dass es der gleiche Thread ist? Dazu müssen wir in die "Tiefen" der WinAPI absteigen.

    Jede GUI Anwendung hat einen Nachrichtenthread. Dieser hat eine Nachrichtenschlaufe, welche im groben so aussieht:

    MSG msg;
    BOOL bRet;
    
    while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    }
    

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms644927.aspx#loop

    DispatchMessage leitet die Nachricht weiter an denjenigen, welcher die Nachricht verarbeitet. Wenn du nun einen Modalen Dialog aufrust ( MessageBox.Show ), dann wird dort drin eine eigene Nachrichtenschlaufe durchlaufen, aber dies macht der gleiche Thread. In dieser Nachrichtenschlaufe, wird dann die zweite Nachricht empfangen und enstprechend demjenigen übergeben, welcher diese verarbeitet, heisst in diesem Fall deiner MyNativeWindow Instanz. Wodurch dann dein Code ein zweites Mal abgearbeitet wird, vom gleichen Thread wodurch der Lock nicht greift, und es wird die zweite MessageBox angezeigt. Darin läuft dann erneut eine Nachrichtenschlaufe, wodurch dann auch eine dritte Nachricht so empfangen werden könnte, usw. usf. 😉

    Grüssli



  • Vielen Dank für deine ausführliche Antwort 🙂
    Viele Grüße


Anmelden zum Antworten