前節では、コールバックからデバッグ領域に表示するといったものでした。
これだけの単純な仕組みであっても 自分なりの制作物を展開していくことが出来ることでしょう。
#include <windows.h> using namespace System; using namespace System::Drawing; using namespace System::Windows::Forms; public ref class ACHelpForm : public Form { public: static ACHelpForm^ f; // 自分自身の置き場 public: ACHelpForm() { SetFormAttr(); // 最初は非表示 this->Visible = false; } public: // 入力補完の候補リストのどれかを選択している時に呼ばれる。 void Update(HWND hWnd, int iListBoxSelectedIndex, String^ strListBoxSelectedItem, int iItemHeight) { RECT rect; GetWindowRect(hWnd, &rect); this->Left = rect.right + 24; this->Top = rect.top; this->Width = (rect.right - rect.left) * 2; this->Height = 160; this->Show(); } protected: // 独立したアプリケーショではなく、子窓のように見せるための工夫 void SetFormAttr() { //タイトルバーを消す。秀丸の中のウィンドウかのように振る舞うための工夫。 this->ControlBox = false; this->Text = ""; this->FormBorderStyle = ::FormBorderStyle::None; this->BackColor = ::Color::Gray; } // このフォームが表示された際にアクティブにならないようにする property bool ShowWithoutActivation { virtual bool get() override { return true; } } // このフォームがマウスクリックされた際にアクティブにならないようにする。 virtual void WndProc(Message %m) override { if (m.Msg == WM_MOUSEACTIVATE) { m.Result = (IntPtr)MA_NOACTIVATE; return; } Form::WndProc(m); } }; extern "C" __declspec(dllexport) int OnCreate(HWND hWnd, LPCTSTR szFileName) { // ウィンドウの作成 if (ACHelpForm::f == nullptr || ACHelpForm::f->IsDisposed) { ACHelpForm::f = gcnew ACHelpForm(); } return TRUE; } extern "C" __declspec(dllexport) int OnListBoxSelectedIndexChanged(HWND hWnd, int iListBoxSelectedIndex, LPCTSTR szListBoxSelectedItem, int iItemHeight) { // そのまま伝達 ACHelpForm::f->Update(hWnd, iListBoxSelectedIndex, gcnew String(szListBoxSelectedItem), iItemHeight); return TRUE; } extern "C" __declspec(dllexport) int OnDestroy(HWND hWnd) { // ウィンドウの破棄 if (ACHelpForm::f) { ACHelpForm::f->Close(); } // このOnDestroyの後に、インスタンスが残っているのに任せるのは不安である。明示的に解放 if (ACHelpForm::f) { OutputDebugString(L"明示解放\n"); delete ACHelpForm::f; } return TRUE; }
再度コンパイルし、「HmAutoCompleteExPlug.dll」を秀丸ディレクトリにコピーしましょう。
秀丸が立ち上がりっぱなしだと、コピー出来ないので、一旦秀丸を終了させる必要があります。
再び、.plファイルを読み込んで、何か入力補完を出し、単語を選択してみましょう。
以下のように、ねずみ色のウィンドウが表示されたでしょうか。
大切なことはこのウィンドウが、
ということです。
全体としては、.NETのフォームアプリケーションの代表的な形そのものです。
「System.Windows.Forms.Form」から継承しているため、ボタンやラベルや描画など、
便利なものが全て極めてわかりやすい形で利用可能です。
とはいえ、おそらくあまり見慣れない記述もあるため、要点だけピックアップしましょう。
// 独立したアプリケーショではなく、子窓のように見せるための工夫 void SetFormAttr() { //タイトルバーを消す。秀丸の中のウィンドウかのように振る舞うための工夫。 this->ControlBox = false; this->Text = ""; this->FormBorderStyle = ::FormBorderStyle::None; this->BackColor = ::Color::Gray; } // このフォームが表示された際にアクティブにならないようにする property bool ShowWithoutActivation { virtual bool get() override { return true; } } // このフォームがマウスクリックされた際にアクティブにならないようにする。 virtual void WndProc(Message %m) override { if (m.Msg == WM_MOUSEACTIVATE) { m.Result = (IntPtr)MA_NOACTIVATE; return; } Form::WndProc(m); }
これらは、いずれも先ほどの
「フォーカスを取らない・アクティブにしない」といったことを実装するための工夫です。
// 入力補完の候補リストのどれかを選択している時に呼ばれる。 void Update(HWND hWnd, int iListBoxSelectedIndex, String^ strListBoxSelectedItem, int iItemHeight) { RECT rect; GetWindowRect(hWnd, &rect); this->Left = rect.right + 24; this->Top = rect.top; this->Width = (rect.right - rect.left) * 2; this->Height = 160; this->Show(); }
この部分は入力補完窓の位置に合わせて、自分自身(Form)が位置や大きさを決めている部分です。
単語補完ウィンドウが大きい人は、このフォームも大きくなり、小さい人は小さくなるということです。