ContextMenuStripをタスクバー上に表示する

投稿者: shuichi, タグ: ,,,, 投稿日時: 2006/10/28 04:38

.NET Framework 2.0では.NET Framework 1.xのContextMenuの代わりにContextMenuStripというコントロールが追加されました。このContextMenuStripは多機能で便利ですが、タスクバー上に表示させようとするとうまく表示できません(タスクバーに重ならないように表示される)。SHAppBarMessageでデスクトップツールバーを作成したときなどは困るんじゃないかと。ということでContextMenuStripをタスクバー上に表示させるためにいろいろと調べてみました。

最初に注目したのはNotifyIcon。NotifyIconにContextMenuStripを設定すると正常にタスクバー上に表示されます。MSIL逆アセンブラでNotifyIconを覗いてみると、ContextMenuStripのShowInTaskbarというプライベートメソッドを呼び出していることが分かります。とりあえず、

contextMenuStrip.GetType().InvokeMember(
    "ShowInTaskbar",
    System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.InvokeMethod |
    System.Reflection.BindingFlags.Instance,
    null,
    contextMenuStrip,
    new Object[] { Cursor.Position.X, Cursor.Position.Y } );

とすることでcontextMenuStripをタスクバー上に表示させることができました。

ただし、この方法では何故かメニューが常にマウスポインタの右上に表示されるようです。いまいちスッキリしないのでShowInTaskbarメソッドの中をさらに覗いてみると、ToolStripDropDownにWorkingAreaConstrainedプロパティが存在するらしい。強制的に作業領域に表示させるという意味なので、

contextMenuStrip.GetType().InvokeMember(
    "WorkingAreaConstrained",
    System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.SetProperty |
    System.Reflection.BindingFlags.Instance,
    null,
    contextMenuStrip,
    new Object[] { false } );
contextMenuStrip.Show( Cursor.Position );

としてみるとうまく表示させることができました。ただし、メニューが表示されるとWorkingAreaConstrainedがtrueに設定されるようなので、表示させる前に毎回WorkingAreaConstrainedをfalseに設定しないと駄目なようです。

これらの方法は本来アクセスできないメソッドやプロパティに強引にアクセスしているわけで、実際はこのような方法は好ましくありません。とりあえずこのような方法もあるというだけです。

.NETのWildcard(ワイルドカード)クラス

投稿者: shuichi, タグ: ,,, 投稿日時: 2005/09/16 17:00

ファイル名を指定するときなどに用いるワイルドカードを.NETで扱う方法がCode ProjectのConverting Wildcards to Regexesにあります。タイトルのとおりワイルドカードを正規表現に変換しているだけですけど、このようにWildcardクラスを定義するとワイルドカードを直感的に扱えますね。

そういえばファイル検索やウェブ検索で正規表現を扱えたらなぁってたまに思うんですけど、デスクトップ検索アプリケーションなどで対応しているものありますかね。

C#(.NET)におけるメッセージフック

投稿者: shuichi, タグ: ,,,, 投稿日時: 2005/09/04 22:17

昔にVisual Basicをやっていたころ色々と凝ったことをやろうとするとVisual Basicの標準機能では実現できないということが多くありました。こういう時はサブクラス化でメッセージをフックするのが最終手段だったのですが、まぁこれが面倒くさい。最初からVisual C++などで書いたほうが良かったと思うくらいでした。

で、C#やVisual Basic.NETなどの.NET対応の言語においてコントロールに送られてくるメッセージを受け取るには、コントロールのクラスを継承してWndProcをオーバーライドすればメッセージを処理することができます。継承のできなかったVisual Basicと比較するとかなり扱いやすくなっていると思います。

一応これで十分なのですが他にも方法があり、Eco-Softさんのコントロールのサブクラス化(フック)を行うに書かれているように、Windows APIを用いる方法もあります(GCHandle.Allocがポイントなんですよね)。これはVisual Basicにおけるサブクラス化と同じ方法なんですけどね…。

また、さらにMemory of the futureさんのNativeWindowクラスを用いたサブクラス化を見て知ったのですが.NETのNativeWindowクラスを用いる方法があるようです。

自分のコントロールのメッセージを処理したい場合は継承してWndProcのオーバーライドでいいと思いますが、他のコントロールに送られてくるメッセージを拝借してこちら側で処理をしたい場合などにはNativeWindowクラスを用いる方法がいいかもしれませんね。

The Code ProjectやCodeGuruで面白いサンプルコードを見つける

投稿者: shuichi, タグ: ,,, 投稿日時: 2005/08/15 23:09

お盆休み中は暇でしたので久しぶりにC#で遊んでいました。まぁ、C#初心者なのでコードを書いていると案の定つまずきます。.Net Framework SDKに付属しているドキュメントを読んでもよくわからないときには以下のサンプルコードやTipsが多数公開されている便利なサイトを。

すべて有名なサイトですね…。The Code ProjectとCodeGuruは英語ですが、かなりおすすめです。適当に記事を見ていくだけでもなかなか面白いですよ。