申し訳ありませんが、これはそれほど問題ではありませんが、これらの特定の問題を抱えている人々を支援するためのものです。私が取り組んでいる問題は、シリアルI / Oを使用する必要がありますが、主にWindowsCE6.0で実行されています。しかし、最近、アプリケーションをWindowsでも動作させることができるかどうか尋ねられたので、この問題の解決に着手しました。私は、誰かが私が探していた答えを持っているかどうかを確認するためにかなりの時間を費やしました、そしてそれはすべて、多くの誤った情報といくつかの例では基本的に間違っていたものとして出くわしました。それで、この問題を解決したので、私は自分の発見をみんなと共有して、これらの困難に遭遇した人が答えを得ることができるようにしたいと思いました。
Windows CEでは、OVERLAPPED I/Oはサポートされていません。これは、シリアルポートを介した双方向通信が非常に面倒になる可能性があることを意味します。主な問題は、シリアルポートからのデータを待機しているときに、データを送信できないことです。これを行うと、読み取り操作が完了するかタイムアウトになるまでメインスレッドがブロックされます(タイムアウトを設定したかどうかによって異なります)。
シリアルI/Oを行うほとんどの人と同様に、シリアルポートを読み取るためにリーダーシリアルスレッドを設定しました。これは、EV_RXCHARマスクを指定したWaitCommEvent()を使用してシリアルデータを待機していました。ここで、WindowsとWindowsCEで問題が発生します。
例として、このような単純なリーダースレッドがある場合:-
UINT SimpleReaderThread(LPVOID thParam)
{
DWORD eMask;
WaitCommEvent(thParam, &eMask, NULL);
MessageBox(NULL, TEXT("Thread Exited"), TEXT("Hello"), MB_OK);
}
明らかに、上記の例では、シリアルポートなどからデータを読み取っていません。また、thParamには通信ポートなどへの開いたハンドルが含まれていると想定しています。現在、問題はWindowsでスレッドが実行され、 WaitCommEvent()、リーダースレッドはシリアルポートデータを待ってスリープ状態になります。さて、それは問題ありませんが、...このスレッドを終了してMessageBox()を表示するにはどうすればよいですか?実は、これは実際にはそれほど簡単ではなく、シリアルI/Oの実行方法におけるWindowsCEとWindowsの根本的な違いです。
Windows CEでは、SetCommMask(COMMPORT_HANDLE、0)やCloseHandle(COMMPORT_HANDLE)など、WaitCommEvent()を失敗させるためのいくつかの操作を実行できます。これにより、スレッドを適切に終了できるため、シリアルポートを解放して、データの送信を再開できます。ただし、これらはどちらもWindowsでは機能せず、どちらも呼び出し元のスレッドをスリープ状態にして、WaitCommEvent()の完了を待機します。では、WindowsでWaitCommEvent()をどのように終了しますか?通常、OVERLAPPED I / Oを使用し、スレッドブロッキングは問題になりませんが、ソリューションはWindows CEとも互換性がある必要があるため、OVERLAPPED I/Oはオプションではありません。WindowsでWaitCommEvent()を終了するためにできることが1つあります。それは、CancelSynchronousIo()関数を呼び出すことです。これにより、WaitCommEvent()が終了しますが、これはデバイスに依存する可能性があることに注意してください。CancelSynchronousIo()の主な問題は、Windows CEでもサポートされていないことです。そのため、この問題にそれを使用するのは運が悪いです。
それで、どうやってそれをしますか?実際、この問題を解決するには、Windows CEでサポートされているWindowsでこの関数を終了する方法がないため、WaitCommEvent()を使用することはできません。これにより、ReadFile()が残り、NON OVERLAPPED I / Oの読み取り中に再びブロックされ、CommTimeoutsで機能します。
ReadFile()とCOMMTIMEOUTS構造体を使用するということは、シリアルデータを待機するタイトなループが必要になることを意味しますが、大量のシリアルデータを受信していない場合は、問題にはなりません。また、小さなタイムアウトでループを終了するイベントにより、リソースがシステムに戻され、100%の負荷でプロセッサに負荷がかからないようになります。以下は私が思いついた解決策であり、改善できると思われる場合はフィードバックをいただければ幸いです。
typedef struct
{
UINT8 sync;
UINT8 op
UINT8 dev;
UINT8 node;
UINT8 data;
UINT8 csum;
} COMMDAT;
COMSTAT cs = {0};
DWORD byte_count;
COMMDAT cd;
ZeroMemory(&cd, sizeof(COMMDAT));
bool recv = false;
do
{
ClearCommError(comm_handle, 0, &cs);
if (cs.cbInQue == sizeof(COMMDAT))
{
ReadFile(comm_handle, &cd, sizeof(COMMDAT), &byte_count, NULL);
recv = true;
}
} while ((WaitForSingleObject(event_handle, 2) != WAIT_OBJECT_0) && !recv);
ThreadExit(recv ? cd.data : 0xFF);
したがって、スレッドを終了するには、event_handleでイベントを通知するだけで、スレッドを適切に終了し、リソースをクリーンアップして、WindowsおよびWindowsCEで正しく機能するようになります。
私が見たすべての人がこの問題に苦しんでいるのを助けることを願っています。