2015-03-13 65 views
-1

我需要複製下面的C++函數在C#:複製MsgWaitForMultipleObjectsEx在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(); 
} 

我認爲重要的關鍵功能是找到一個C#相當於MsgWaitForMultipleObjectsEx。到目前爲止,我在C#中發現的最接近的方法是模擬這種行爲,方法是WaitHandle.WaitAny()。用WaitAny()我可以設置一個計時器,並且還指定當前實例將等待的對象WaitHandle。不過,我的問題是dwWakeMaskdwFlags值,因爲我似乎無法將它們與System.Threading中的任何對象相匹配。我也關注WAIT_IO_COMPLETIONWAIT_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

在「純」.NET中沒有任何東西完全相同。但是因爲你沒有使用p/invoke,所以你沒有真正的Win32 APC,因此並不需要正好一樣,效果也一樣。 (特別是,你不需要警告等待)

爲此,通過WPF SynchronizationContext轉發您的I/O回調,它將通過現有的WPF消息循環傳遞它們。同樣,如果您正在翻譯實際通過HANDLE數組的使用情況,則希望使用Tasks而不是WaitHandleTask的延續也使用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 
+0

這正是我說的!所以我可以在'SynchronizationContext'和'Task'結合中找到我需要的所有東西?你知道我能找到一個這樣的例子嗎?或者,如果也許你可以提供一個小的? – 2015-03-13 19:58:06

+0

@Ericafterdark:'Dispatcher.BeginInvoke'是關鍵的方法,不知道你實際上想做什麼,我不能舉一個例子。你正在使用網絡事件還是在工作線程上完成計算? – 2015-03-13 20:03:03

+0

我認爲這更多的是在網絡事件領域。基本上我的程序通過TCP/IP套接字連接到外部機器。在這部分代碼中,我的程序正在等待來自機器的消息,並處理上面C++代碼中記錄的每個條件,當它們被觸發時。我已經從原始程序的C++代碼中添加了一些評論,可能有所幫助。 – 2015-03-13 20:11:47