我们聘请了一家公司将一个控制某些工业机械的旧VB6 DLL转换为C#。旧的VB6代码具有“暂停”例程,由睡眠调用和 DoEvents 组成,以便在睡眠时,DLL中的计时器和套接字事件仍然会被处理。 DoEvents转换为
System.Windows.Forms.Application.DoEvents();
我不是VB6程序员,但我的理解是VB6实际上是单线程的,因此长时间休眠会关闭所有内容,包括计时器和套接字事件处理。
当代码转换为C#时,暂停例程看起来像这样。 。 。
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);
}
}
在.Net中,计时器和套接字事件在它们自己的线程中运行(我在这个转换后的代码中的大部分工作都是为了使它成为线程安全的!)所以 DoEvents()< / strong>买我们。但MSDN说
调用此方法会导致当前线程暂停 处理所有等待窗口的消息。
那么我们应该将这些 DoEvents()保留在其他类型的事件(不是定时器或套接字回调)中吗?或者它们在.Net / C#上下文中是多余的?
答案 0 :(得分:10)
DoEvents
创建了一个额外的消息循环。它只是一个读取消息,处理它,然后读入下一条消息的循环,直到它收到一条消息,它应该停止,或者没有要处理的消息。调用Application.Run
会为您的应用程序创建初始消息循环。从其中一个处理程序中为这些消息创建其他嵌套消息循环可能会导致all sorts of problems,因此应该避免它,除非您非常熟悉它的作用以及在什么情况下可以正确使用它。 / p>
在大多数情况下,您的程序应该只是异步,而不是创建一个额外的消息循环。在一段时间之后,你应该使用Timer
这样的方法来执行一个方法,而不是阻塞当前线程,而不是阻塞当前线程。
在.Net中,计时器和套接字事件在它们自己的线程中运行
实际等待Timer的时间过去,或者套接字得到响应,完成,而不使用任何线程。没有线程坐在那里睡觉,而是操作本质上是异步的。至于用于执行事件处理程序的线程,这将有所不同。一些计时器将使用一个线程池,一些是UI线程,一些是可配置的,可以做任何一个。套接字可能只是使用线程池线程。
答案 1 :(得分:5)
VB6 DoEvents暂停当前过程的处理(这是唯一的方法),处理应用程序消息队列中的所有消息(因此事件可能会触发),从而使您的过程可重入。然后它调用Windows API函数Sleep(0)。 Windows然后做它的消息。最后,您的程序将重新启动。
好处是,当你遇到多线程的问题时,你仍然是单线程的,所以像If InProc = True then Exit Function:InProc = True:...:InProc = False:End Function
这样简单的代码将起作用,因为它不能在中途被抢占。
答案 2 :(得分:0)
通常,您不想使用Application.DoEvents()
。如何使用它的一个不好的做法示例是确保在继续在同一个线程上执行长时间运行之前光标更改为等待光标(该操作应该在单独的线程上运行)。
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;
在您的具体情况下,看起来他们试图将其用作黑客来伪造UI比实际响应更快。
答案 3 :(得分:0)
您应该在循环中使用它:
await System.Windows.Threading.Dispatcher.Yield()
创建一个等待对象,该对象异步将控制权交还给 当前的调度员,并为调度员提供机会 处理其他事件。
这要好得多,并且从根本上为您创建了UI的延迟加载。
答案 4 :(得分:-1)
*Processes all Windows messages currently in the message queue.*
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents%28v=vs.110%29.aspx
它允许Window Forms处理从Window Message Pump等待它的任何消息。 因此,所有代码都会等待一半的时间,然后处理消息并再次等待。