Das mit dem Schwert war auf: Mehrere Wege, jeder Weg ist lang um ihn zu gehen (testen) aber die Zeit reicht nur für einen Weg
Jo, genau das
Da es im Moment erstmal halbwegs funktioniert werd ich das auch vertagen. Wenn später Zeit dafür da ist gut, sonst bleibt es halt so wie es ist - mit nem eigenen Scheduler in Application.Idle.
Was DoEvents angeht: bringt in meinem Fall nix (wenn ich das richtig einschätze). DoEvents arbeitet alle Messages ab, richtig. Allerdings passiert bei mir (ohne den Trick mit Application.Idle) folgendes: in einer Form sitzen ein Haufen Video Controls. Video Control 1 bekommt nun ein Invalidate(). Das führt nicht dazu dass eine Message gepostet wird, sondern es wird die Update-Region für das entsprechende Fenster angepasst. Beim nächsten GetMessage bzw. PeekMessage wo keine andere Nachricht gefunden wird, gehen die Funktionen her und gucken ob es irgendwelche Fenster gibt wo die Update-Region nicht "leer" ist. Ist das der Fall wird für das erste gefundene Fenster eine WM_PAINT synthetisiert. WM_PAINT landet also niemals in der Queue, wird daher also auch nicht gereiht.
Nun fängt der Paint Handler dieses Controls an zu laufen. Das dauert leider eine Zeit lang. Nehmen wir an dass es so lange dauert dass neue Frames für alle Controls in dieser Zeit ankommen. In der entsprechenden "RecieveFrame" Funktion (die asynchron in einem anderen Thread läuft) wird nun mittels BeginInvoke ein Callback abgesetzt um den entsprechenden Code im UI Thread auszuführen. BeginInvoke macht intern im Prinzip ein PostMessage.
Wenn das nächste mal GetMessage/PeekMessage ausgeführt wird ist die Queue also nichtmehr leer, d.h. die von BeginInvoke verwendete Message wird abgearbeitet. Der so ausgeführte Code macht wieder ein Invalidate, und zwar für alle Controls, da ja für jedes Control ein BeginInvoke gemacht wurde.
Erst nachdem alle BeginInvoke fertig abgearbeitet sind ist die Queue also wieder leer, und erst dann macht sich GetMessage/PeekMessage wieder auf die Suche nach Fenstern deren Update-Region nicht leer ist.
Und hier kommt der entscheidende Punkt: Windows nimmt einfach das erste gefundene Fenster dessen Update-Region nicht leer ist, und schickt diesem eine WM_PAINT. Wenn nun also Invalidate() so schnell für alle Controls aufgerufen wird, dass quasi immer alle Controls eine nicht-leere Update-Region haben wenn GetMessage/PeekMessage zu suchen anfängt, dann wird immer nur ein Control neu gezeichnet - immer dasselbe (das erste gefundene, und die Reihenfolge in der gesucht wird ändert sich ja nicht, ist einfach die Reihenfolge in der die Controls angelegt wurden)! Würde Windows dagegen das Fenster auswählen welches schon am längsten nichtmehr neu gezeichnet wurde, wäre das Problem gegessen. (Genau das "simuliere" ich ja auch über meinen Scheduler)
Und... da DoEvents im Prinzip auch nur einen Message-Loop enthält, bringt das in dem Fall nix. DoEvents würde schlicht und einfach NIE mehr verlassen werden, da es IMMER noch eine Message findet die es zu bearbeiten gilt. Sei es nun eine aus der Queue oder eine synthetisierte WM_PAINT.
Mit WM_TIMER ist es im Prinzip dasselbe wie mit WM_PAINT. WM_TIMER wird auch erst von GetMessage/PeekMessage synthetisiert wenn keine anderen Messages mehr vorhanden sind, und ein Timer gefunden wird der "abgelaufen" ist.