シンプルに説明するために,若干汚いコードを書いています.
VisualStudioとC#の連携です.自分自身が不慣れなので,図を交えてすこし丁寧に説明します.
まずはメニューからフォームを追加します.

フォームに名前をつけてください.これがFormクラスの名前になります.

共通言語ランタイムサポートをONにします.「はい(Y)」をクリックしてください.

この変はVBを使ったことがある人なら問題ないでしょう.

*2008年6月27日追記: VC2008を使っていると,うまくツールボックスを使えない障害があります.
これは.Net Frameworkの更新を怠っているからですが,「ソリューションのプロパティ」→「共通プロパティ」→「Frameworkと参照」で,「対象とするFramework(G)」を「.Net
Framework 2.0」に選択すれば直ります.
プロパティビューからボタンのキャプションやオブジェクト名を変更できます.

ボタンとエディットボックスを追加しました.

最終的にそれぞれのプロパティの変更点は以下のようになっています.
| オブジェクト | button1 | button2 | TextBox | |
| プロパティ | デザイン−Name | countUpButton | sendButton | textBox1 |
| 表示−Text | CountUp(&C) | Send(&S) | Please Input Message | |
コードを編集していきます.とりあえず表示部分だけ説明しますね.Javaで言うJNIに良く似たインタフェースです.

ここまでの編集で作成したソースファイルは3つ.
SettingPanel.cppはC++コード.SettingPanel.hはC#コードになっています.不思議ですがSettingPanel.cppからSettingPanel.hをインクルードしてもコンパイルが通ります.これは共通言語ランタイムサポートをONにしている恩恵です.
つまりSettingPanel.cppを仲介役として,C#コードであるFormにアクセスができ,またその逆も可能ということです.
#include "SettingPanel.h"
#include "SettingPanel.h"
using namespace PeriodicConsoleOut;
void SettingPanel_createForm(void) {
Application::Run(gcnew SettingPanel());
}
これで表示するための関数が実装されました.ただもともとのコンポーネントのコードから,このcreateFormメソッドを呼び出さなくてはなりません.
int main (int argc, char** argv)
{
RTC::Manager* manager;
manager = RTC::Manager::init(argc, argv);
〜中略〜
// run the manager in blocking mode
// runManager(false) is the default.
manager->runManager();
// If you want to run the manager in non-blocking mode, do like this
// manager->runManager(true);
return 0;
}
void SettingPanel_createForm(void); //SettingPanel.cpp内のグローバル関数を使用するために,関数を宣言.
int main (int argc, char** argv)
{
RTC::Manager* manager;
manager = RTC::Manager::init(argc, argv);
〜中略〜
// run the manager in blocking mode
// runManager(false) is the default.
//manager->runManager(); //デフォルトのrunManagerメソッドをコメントアウト.
// If you want to run the manager in non-blocking mode, do like this
manager->runManager(true); //runManagerメソッドをノンブロッキングモードで呼び出すと,コントロールがすぐに返ってきます.
SettingPanel_createForm(); //そして直ちにFormを作成します.createFormメソッド内のApplication::Run()メソッドはモーダルなFormを作成するので,Formを閉じない限りmain関数は終了しません.
return 0;
}
それぞれのボタンをダブルクリックすると,自動的にイベントハンドラコードが生成されます.
今回追加した二つのボタンを両方ともダブルクリックすると,下記のようなコードが生成されます.
#pragma endregion
private: System::Void countUpButton_Click(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void sendButton_Click(System::Object^ sender, System::EventArgs^ e) {
}
};
ちなみに,ソリューションエクスプローラからSettingPanel.hを開いても,デザインビューしか開きません.コードを変更するときは右クリックをして,メニューからコードの表示を選びます.

#include <string>
std::string stringBuffer= 0; //このようにヘッダーファイル(C#コード)の前で変数を宣言することで,C#コード内で変数を操作することができるようになる.
#include "SettingPanel.h"
using namespace PeriodicConsoleOut;
void SettingPanel_createForm(void) {
Application::Run(gcnew SettingPanel());
}
ここでコードの変更
文字列はC#のマネージドコード上の形式と,アンマネージメモリ上の形式が異なりますので若干面倒です.
#pragma endregion
private: System::Void countUpButton_Click(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void sendButton_Click(System::Object^ sender, System::EventArgs^ e) {
IntPtr ptr = Marshal::StringToHGlobalAnsi(this->textBox1->Text); //テキストボックスの文字をアンマネージメモリに移動し,さらにANSI形式に変換します.
stringBuffer = static_cast<const char*>(ptr.ToPointer()); //んで代入.
}
};
RTコンポーネント本体からもstringBufferを参照できます.
#include <string>
extern std::string stringBuffer; //外部変数にアクセスするために,変数名を宣言します.
RTC::ReturnCode_t PeriodicConsoleOut::onExecute(RTC::UniqueId ec_id)
{
std::cout << "String = " << stringBuffer << std::endl; //このように直接アクセスできます.
return RTC::RTC_OK;
}
public: int count; //メンバ変数を追加
private: System::Void countUpButton_Click(System::Object^ sender, System::EventArgs^ e) {
count++; //ボタンが押されたらインクリメント
}
private: System::Void sendButton_Click(System::Object^ sender, System::EventArgs^ e) {
IntPtr ptr = System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(this->textBox1->Text);
stringBuffer = static_cast<const char*>(ptr.ToPointer());
}
C++コード側は面倒です.今回はSettingPanelクラスのオブジェクトがグローバル変数などになっていませんから.
そこで,Formを作成する際にApplicationクラスメソッドのRunをつかいましたよね.Form本体はApplicationクラスが管理しているはずなので,そちらを参照するコードを書いてみました.
int SettingPanel_getCount() {
return ((PeriodicConsoleOut::SettingPanel^)Application::OpenForms[0])->count;
}
ApplicationクラスからOpenFormsメンバを介してFormの参照を受けとり,SettingPanelクラスへの参照にキャストしてからcountにアクセスしています.「^」はマネージドメモリに対するポインタを意味していますが,「*」の代わりだと思う程度でいいです.
んでRTコンポーネント側からはSettingPanel_getCountメソッドを介してcountパラメータを受け取ります.
#include <string>
extern std::string stringBuffer;
int SettingPanel_getCount(void); //SettingPanel.cpp内のSettingPanel_getCount関数にアクセスするために関数名を宣言します.
RTC::ReturnCode_t PeriodicConsoleOut::onExecute(RTC::UniqueId ec_id)
{
std::cout << "Text = " << stringBuffer << std::endl;
std::cout << "Count = " << SettingPanel_getCount() << std::endl; //関数を呼び出せばcountの値が返ってきます.
return RTC::RTC_OK;
}
これまでどおりでよろしくです.
コンポーネントをアクティブ化すれば,ボタンを押すと変更がコンソール出力に反映されているのがわかると思います.
PeriodicConsoleOutGUI.zip (ver. 0.4.1)
PeriodicConsoleOutGUI042.zip (ver. 0.4.2)