2014-11-26 13 views
7

Wir stellten eine Firma ein, um eine alte VB6 DLL zu konvertieren, die einige Industriemaschinen nach C# steuert. Der alte VB6-Code hatte "Pause" -Routinen, die aus Schlafanrufen bestanden, die mit DoEvents gesprenkelt wurden, so dass während des Schlafens Timer- und Socket-Ereignisse in der DLL noch verarbeitet würden. Die DoEvents wurdenWas tun DoEvents() in C# eigentlich?

umgewandelt
System.Windows.Forms.Application.DoEvents(); 

Ich bin kein VB6 Programmierer, aber mein Verständnis ist, dass VB6 tatsächlich single-threaded ist und so ein langer Schlaf würde Handhabung alles, einschließlich Timer und Buchse Veranstaltung geschlossen.

Wenn der Code in C# umgewandelt wurde, sahen die Pausenroutinen so aus. . .

public static void pauseit_ms(ref int milliseconds) 
{ 
    try 
    { 
     Sleep(milliseconds/2); 
     System.Windows.Forms.Application.DoEvents(); 
     Sleep(milliseconds/2); 
    } 
    catch (Exception exc) 
    { 
     LogException("pauseit_ms", exc); 
    } 
} 

In .Net, Timer und Socket-Ereignisse in ihrem eigenen Threads ausgeführt (in diesem die meisten meiner Arbeit umgewandelt Code war zu versuchen, es Thread-sicher zu machen!) So offensichtlich, es ist nicht das, was die DoEvents () kauft uns. Aber die MSDN sagt

Der Aufruf dieser Methode bewirkt, dass der aktuelle Thread ausgesetzt werden, während alle wartenden Fenster Nachrichten verarbeitet werden.

Also sollten wir verlassen diese DoEvents() in so andere Arten von Veranstaltungen (nicht Rückrufe Timer oder Buchse) nicht blockiert werden? Oder sind sie in einem .Net/C# -Kontext überflüssig?

+1

FYI, 'DoEvents' ist nicht Teil von C#. Es ist Teil von .NET Framework. –

+0

Klingt so, als hätte die Firma, die Sie angestellt haben, eine 1: 1-Konvertierung durchgeführt, ohne sich darum gekümmert zu haben, wie der Code tatsächlich funktioniert. –

Antwort

8

DoEvents erstellt eine zusätzliche Nachrichtenschleife. Es ist nur eine Schleife, die eine Nachricht einliest, verarbeitet und dann die nächste Nachricht einliest, bis sie eine Nachricht erhält, dass sie aufhören soll oder keine Nachrichten zu verarbeiten hat. Der Aufruf Application.Run erstellt die erste Nachrichtenschleife für Ihre Anwendung. Das Erstellen zusätzlicher geschachtelter Nachrichtenschleifen in einem der Handler für diese Nachrichten kann all sorts of problems verursachen und sollte daher vermieden werden, es sei denn, Sie sind mit dem Verfahren und den Umständen, unter denen Sie es richtig verwenden können, vertraut.

In den meisten Fällen sollte Ihr Programm nicht eine zusätzliche Nachrichtenschleife erstellen, sondern einfach asynchron sein. Anstatt den aktuellen Thread für einen bestimmten Zeitraum zu blockieren, sollten Sie eine Methode wie Timer verwenden, um eine Methode nach einer bestimmten Zeit auszuführen, ohne den aktuellen Thread zu blockieren.

In .Net, Timer und Socket-Ereignisse in ihrem eigenen Threads laufen

Die tatsächliche Warte für die Zeit des Timer verstreichen, oder für die Buchse eine Antwort zu bekommen, ohne Verwendung erfolgt von irgendeinem Thread überhaupt. Es gibt keinen Thread, der dort schläft, sondern die Vorgänge sind von Natur aus asynchron. Was den Thread betrifft, der zum Ausführen der Ereignisbehandlungsroutinen verwendet wird, wird dies variieren. Einige Timer verwenden einen Thread-Pool, einige den UI-Thread und einige sind konfigurierbar und können beides tun. Der Socket verwendet wahrscheinlich nur einen Thread-Pool-Thread.

+2

"Wenn es keine Nachrichten gibt, wird es nur warten bis es eins bekommt." - Geht es um 'DoEvents'? Wenn dies der Fall ist, ist dies nicht wahr. 'DoEvents' wartet nicht auf Nachrichten; Es verarbeitet alles, was es findet, und beendet es, wenn es keine mehr gibt. (Siehe http://msdn.microsoft.com/en-us/library/aa262728(v=vs.60).aspx) – rskar

+0

Weitere Informationen zu VB6 DoEvents finden Sie unter http://support.microsoft.com/kb/158175 – rskar

+0

Dies gilt nicht für das "Erstellen" einer zusätzlichen Nachrichtenschleife. Alles, was "DoEvents" tut, ist, die vorhandene Nachrichtenschleife erneut einzugeben. – Enigmativity

0

Im Allgemeinen möchten Sie nicht Application.DoEvents() verwenden. Ein übliches Beispiel dafür, wie es verwendet werden kann, besteht darin, sicherzustellen, dass der Cursor in den Wartecursor wechselt, bevor mit einer langen Ausführung des gleichen Threads fortgefahren wird (der Vorgang sollte wirklich in einem separaten Thread ausgeführt werden).

Cursor.Current = Cursors.WaitCursor; 
//Makes sure this change takes effect instead of being blocked by the next line. 
//NOT SUPER RELIABLE 
Application.DoEvents(); 

//Do long work here 
Cursor.Current = Cursors.Default; 

In Ihrem speziellen Fall, es sieht aus wie sie es als ein Hack zu fälschen die UI ist ein wenig stärker auf als es tatsächlich ist zu verwenden versuchen.

3

VB6 DoEvents setzt die Verarbeitung der aktuellen Prozedur aus (dies ist die einzige Möglichkeit, dass dies passieren kann), verarbeitet alle Nachrichten in der Anwendungsnachrichtenwarteschlange (sodass Ereignisse ausgelöst werden können) und macht Ihre Prozedur somit wiedereintrittsfähig. Es ruft dann die Windows-API-Funktion Sleep (0) auf. Windows macht dann Nachrichten. Am Ende wird die Prozedur neu gestartet.

Die gute Sache ist, dass, während Sie die Probleme des Multithreading bekommen, Sie immer noch single-threaded, so einfacher Code wie If InProc = True then Exit Function:InProc = True:...:InProc = False:End Function wird funktionieren, wie es nicht auf halbem Weg durchschritten werden kann.