-1

I need to replicate the following C++ function in 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();
}

I believe the key to this function is finding a C# equivalent to MsgWaitForMultipleObjectsEx. So far the closest method I've found in C# that emulates this behavior is the WaitHandle.WaitAny() method. With WaitAny() I can set a timer and also specify WaitHandle objects for which the current instance will wait. However, my trouble is with the dwWakeMask and dwFlags values because I can't seem to match them with any objects in System.Threading. I'm also concerned with WAIT_IO_COMPLETION and WAIT_OBJECT_0.

This is my C# code so far:

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;
}

I've read about WaitHandle.SafeWaitHandle and that it "Gets or sets the native operating system handle". Am I able to use SafeWaitHandle to obtain access to native values like QS_ALLINPUT? If not, how can I add to my approach to replicate the behavior of the C++ function?

Note: I have to do this without P/Invoke or any sort of wrapper.

Eric after dark
  • 1,768
  • 4
  • 31
  • 79

1 Answers1

0

There is nothing in "pure" .NET that does exactly the same. But since you aren't using p/invoke, you don't have real Win32 APCs and therefore don't need exactly the same, just the same effect. (in particular, you don't need the alertable wait)

For that, forward your I/O callbacks through the WPF SynchronizationContext, that will pass them through the existing WPF message loop.

Similarly, if you were translating usage that actually passed a HANDLE array, you'd want to use Tasks instead of WaitHandle, the continuation for the Task uses the WPF SynchronizationContext also. But your C++ code doesn't use the handle-waiting capability of MWFMO anyway.

Finally, the timeout can use await Task.Delay(timeout) which uses a continuation, per above.

For TCP/IP communication, it might look something like this (based on 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
Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • That's exactly what I'm talking about! So I can find all I need in `SynchronizationContext` combined with `Task`? Do you know of anywhere that I could find an example of this? Or if maybe you could provide a small one? – Eric after dark Mar 13 '15 at 19:58
  • @Ericafterdark: `Dispatcher.BeginInvoke` is the key method, without knowing what you're actually trying to do I can't really give an example. Are you working with network events or completion of a calculation on a worker thread or what? – Ben Voigt Mar 13 '15 at 20:03
  • I think this is more in the network event realm. Basically my program connects to an external machine through a TCP/IP socket. In this portion of the code my program is waiting for messages from the machine and handles each of the conditions documented in the C++ code above when they are triggered. I've added some comments to the C++ code from the original program that might help. – Eric after dark Mar 13 '15 at 20:11
  • @Eric: Some example added, untested. – Ben Voigt Mar 13 '15 at 20:35