たまにVC++ CLI (.NETのC++) を使うと忘れているこのメモです。
.libの設定場所
「ライブラリ」でなく「追加の依存ファイル」と記述されている。Windows標準ライブラリなら「追加のライブラリディレクトリ」は設定しなくてよい。

WORD、DWORDが無いと怒られるとき
win32APIやMFC特有の型WORD、DWORDは、CLIでは追加includeが必要。

オブジェクトの頭^
Java、C#の感覚で書いてしまうとBuildエラーになり悩む。new でなく gcnew もであることもお忘れなく。

.NETクラスライブラリを作るとき
以下を選択。Publicメソッドを普通に書けば、C#等からも利用が可能。MFC ActiveX Controlのように特別な設定はいらない。

.NETクラスライブラリを使うとき
C#等から、CLIで生成したの.dllを使用時に「間違ったプログラムのフォーマットを読み込もうとしました。」とエラーが発生する場合、x86、x64を指定する。C#単体だと「Any CPU」でWindows上で動作するが、、、

オブジェクトの排他制御
MFCではなんとなくでよかったスレッド間のオブジェクト排他制御は、必須になります。デリゲートを使います。デリゲートは .NET 独自概念です。Swfitのとは違います。別スレッドで動作されるイベントの例です。排他ありと無で2分岐作ります。
// 受信が別Threadのため、threadまたぎコントロールアクセスのため、
// デリケード(オブジェクトとメソッドをカプセル化した型)を使う。
// 「受信データ表示」デリゲート型
// メソッドへの引数がデリゲート型の引数になります
delegate void displayReceiveData_Delegate(void);
displayReceiveData_Delegate^ displayReceiveData_Obj; // 「受信データ表示」デリゲート実体
delegate void displayReceiveError_Delegate(System::IO::Ports::SerialError);
displayReceiveError_Delegate^ displayReceiveError_Obj; // 「受信エラー表示」デリゲート実体
delegate void sendData_Delegate(void);
sendData_Delegate^ sendData_Obj; // 「送信データ」デリゲート実体
/* ****************************************************************************
* 機能名 : シリアルポート受信イベント
* ***************************************************************************/
private: System::Void serialPort1_DataReceived(
System::Object^ sender,
System::IO::Ports::SerialDataReceivedEventArgs^ e
) {
if ( dgrdReceive->InvokeRequired ) { // thread排他が必要か判別
// 「受信データ表示」デリゲート実体を確保。
// デリゲートのメソッドは、Formのメソッドとして宣言し、
// form実体と、メソッド型を、デリゲートに割り当てる。
// &はC++時のおまじない的記述。C#では不要らしい。
displayReceiveData_Obj = gcnew displayReceiveData_Delegate(this, &Form1::displayReceiveData);
// デリゲートを排他ありで呼び出す
this->Invoke(this->displayReceiveData_Obj);
}
else {
displayReceiveData(); // 受信値表示
}
if ( serialPort1->IsOpen ) {
if ( dgrdReceive->InvokeRequired ) { // thread排他が必要か判別
sendData_Obj = gcnew sendData_Delegate(this, &Form1::SendData);
// デリゲートを排他ありで呼び出す
this->Invoke(this->sendData_Obj);
}
else {
SendData(); // 次の送信
}
}
}
シリアルポートの受信などトラフィックの高いデリケートの場合、デッドロック的な事象が発生するようです。その場合は、
formatReceiveData_Obj = gcnew formatReceiveData_Delegate(this, &Form1::formatReceiveData);
// デリゲートを排他無しで呼び出す
// Invokeでは大量受信後、Close でフリーズしてしまう。
this->BeginInvoke( this->formatReceiveData_Obj );
ARRAYによる二次元配列
宣言時は、
array <String^,2/*次元数*/>^ recvFormatedData;
recvFormatedData = gcnew array<String^,2/*次元数*/>( 1/*行*/, 3/*列*/ );
参照時
recvFormatedData[ num, 0 ] =
System::String::Format("{0:00}:{1:00}:{2:00}.{3:000} ",
DateTime::Now.Hour, DateTime::Now.Minute, DateTime::Now.Second,
DateTime::Now.Millisecond );
recvFormatedData[ num, 1 ] = data1;
recvFormatedData[ num, 2 ] = data2;
拡大はできないので、BACKコピーして、新しくnewして中身を転記する。
// CLIでは多次元arrayの拡大はできないため、新しく作ってコピーする。
array <String^,2/*次元数*/>^ backData;
backData = (array <String^,2/*次元数*/>^)recvFormatedData->Clone();
recvFormatedData = gcnew array<String^,2/*次元数*/>( num+1/*行*/, 3/*列*/ );
for( int i = 0; i < num; i++ ) {
recvFormatedData[ num, 0 ] = backData[ num, 0 ];
recvFormatedData[ num, 1 ] = backData[ num, 1 ];
recvFormatedData[ num, 2 ] = backData[ num, 2 ];
}
配列数取得時は、
// 未表示データ行数 ( [0]は配列保持用の空Record )
int datanum = recvFormatedData->GetLength( 0 /*次元数*/ );
Formエディタ
- 意図せずUIダブルクリックしないように注意する。ダブルクリックでイベント自動追加され、要らないのでUndoするとFormが壊れる。イベント自動追加は無効に設定できるようにしてほしいものです。
- UIを別frameに移動するとき、切取り -> 貼付け すると壊れる。ドラック移動だけで別frameの子供に移動できる。
以降、随時追加中...