MFCの選択
C++でWindowsの処理をするのにC++/Cliとか、C++/CXとか、C++/WinRXとかついていけないし、ハードウエア周りの処理なので、MFCでとりあえず実装することにする。
C++のDLLにして、C#でGUI実装のほうが簡単だけど、ちょっと理由があってC++ですべて作成しないといけない。
MFCのUI部と、ハードウエア周りのコードは別にして、ハードウエア周りは標準のC++で作成したいものです。
C++は最新の文法を使いたい。しかしWin32がwchar_tなので、std::stringとうまく調和しない。いろいろ変換をいれる必要がある
std::string 周りの対応
ハードウエア側はstd::stringでデータを取得するが、MFCのUIに表示するときは、whar_tに変換しないといけない。Windowsの設計思想が20年前ですからね。
MFCのCStringAとCStringを使って変換するのが簡単らしい。
std::string str = "ABCDE";
CStringA str2(str.c_str());
CString str3(str2);
エンコードがUTF-8の場合はこの方法ではうまくいかず、MultiByteToWideChar()関数で変換する必要があります。
スレッド
_biginthread などの、Windowsのローカルなスレッド関数は引数が多すぎて理解できないので、std::threadを使用したい。
ただ、メインスレッドでUIをコントロールしないといけないので、メインスレッドにメッセージを送る必要があります。
ワーカースレッド側から、postMessage関数にてWindowsのメッセージをポストし、メインスレッドのメッセージキューから独自のメッセージを処理するメソッドを設定してそちらでUIの更新をおこなうことにします。
Windowsメッセージの定義
ユーザー定義のメッセージを準備します。
#define WM_SAMPLEMSG (WM_APP + 1)
それを取得するメッセージマップをMFCのマクロに追加します。
OnStart とOnStopでスレッド開始、停止をできるようにします。
BEGIN_MESSAGE_MAP(SampleDialog, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_START, &SampleDialog::OnBnClickedButtonStart)
ON_BN_CLICKED(IDC_BUTTON_STOP, &SampleDialog::OnBnClickedButtonStop)
ON_MESSAGE(WM_SAMPLEMSG, SampleDialog::OnMessage)
END_MESSAGE_MAP()
OnMessageメソッドをヘッダに追加
Class SampleDilaog : public CDialogEx
{
///省略
//追加
public:
LRESULT OnMessage(WPARAM w_param, LPARAM l_param);
volatile bool run;
std::thread th;
};
OnBnClickedButtonStart OnBnClickStop実装
void SampleDialog::OnBnClickedButtonStart()
{
run = true;
th= std::thread([&]() -> void {
while(run){
//ハードウエアから何かデータが来る。
if(something) {
//ヒープに割り当てる
std::string *ptr = new std::string("aaaa");
PostMessageW(WM_PHOENIXMSG, 0,(LPARAM) ptr);
}
}
});
}
//スレッド停止
void SampleDialog::OnBnClickedButtonStop()
{
run = false;
}
OnMessageをソースコードに追加
ヒープの文字列データを取得して、リストビューに追加
LRESULT SampleDialog::OnMessage(WPARAM w_param, LPARAM l_param)
{
std::String * data = (Std::String*)l_param;
CStringA dataA = CStringA(*data.c_str());
CString dataB = CString(dataA);
listTag.InsertItem(0,dataB );
delete data;
return 0;
}
コードを実行すると、スレッドからUIへデータが受け渡されます。