我需要在C#中复制以下C ++函数:
void TComThread::CommWaitForAndHandleMessages(int minimum_poll)
{
// Wait for:
// Any of the HANDLES in the WaitFor array, OR
// Any Windows message, OR
// Any Asynchronous Procedure Call (APC) to complete OR
// A timeout after minimum_poll milliseconds
const DWORD ret = MsgWaitForMultipleObjectsEx(0,
NULL, minimum_poll, QS_ALLINPUT, MWMO_ALERTABLE);
// APC: it was already called, so we just return
if (ret == WAIT_IO_COMPLETION)
return;
// Timeout: we just return
else if (ret == WAIT_TIMEOUT)
return;
// Windows message: process messages and return
else if (ret == WAIT_OBJECT_0)
Application->ProcessMessages();
// Error of some kind
else
RaiseLastWin32Error();
}
我相信这个功能的关键是找到一个等同于MsgWaitForMultipleObjectsEx的C#。到目前为止,我在C#中发现的最接近的模拟此行为的方法是WaitHandle.WaitAny()方法。使用WaitAny()
我可以设置一个计时器,并指定当前实例将等待的WaitHandle
个对象。但是,我的问题在于 dwWakeMask 和 dwFlags 值,因为我似乎无法将它们与System.Threading
中的任何对象匹配。我还关注WAIT_IO_COMPLETION
和WAIT_OBJECT_0
。
到目前为止,这是我的C#代码:
private void CommWaitForAndHandleMessages(int minimum_poll)
{
Thread.WaitHandle[] waitHandles = new Thread.WaitHandle[]
{
//This is where I would create my WaitHandle array
};
int ret = Thread.WaitHandle.WaitAny(/* BLANK **/, new TimeSpan(minimum_poll), false);
//Timeout -- return
if(ret == Thread.WaitHandle.WaitTimeout)
return;
}
我已经阅读了WaitHandle.SafeWaitHandle并且它已经获取或设置了本机操作系统句柄"。我是否可以使用SafeWaitHandle
来获取对QS_ALLINPUT
等原生值的访问权限?如果没有,我如何添加到我的方法来复制C ++函数的行为?
注意:我必须在没有P / Invoke或任何类型的包装器的情况下执行此操作。
答案 0 :(得分:0)
"纯粹" .NET完全相同。但是由于你没有使用p / invoke,你没有真正的Win32 APC,因此不需要完全相同,只是效果相同。 (特别是,你不需要警报等待)
为此,通过WPF SynchronizationContext
转发您的I / O回调,它将通过现有的WPF消息循环传递它们。
同样,如果您正在翻译实际传递HANDLE数组的用法,那么您希望使用Tasks而不是WaitHandle
,Task
的延续也使用WPF SynchronizationContext。但是你的C ++代码并没有使用MWFMO的句柄等待功能。
最后,超时可以使用await Task.Delay(timeout)
,使用延续,按上述。
对于TCP / IP通信,它可能看起来像这样(基于 https://stackoverflow.com/a/4036260/103167):
var cts = new CancellationTokenSource();
var recvTask = tcpSocket.ReadAsync(buffer, offset, length, cts.Token);
if (!await recvTask.Wait(3000, cts.Token)) {
cts.Cancel();
uiStatus("MessageTimeout");
return;
}
int bytesReceived = recvTask.Result;
// buffer has been filled in, go ahead and process the message