2011年11月27日日曜日

wpf : UserControlを含んだクラスライブラリ(dll)を動的にロード

UserControlを含んだクラスライブラリ(dll)を動的にロードするサンプルコードです。 ユーザーインターフェース付きのプラグインに対応したソフトを作ることを考えて組んでみました。

各プラグインとのやり取りをするときに使う共通処理を本体側のinterfaceで定義しておきます。 プラグイン側はそのinterfaceを実装したクラスを作成。 本体はSystem.Reflection.Assembly.LoadFromでプラグインのdllを読み込み、そのクラスのインスタンスを作成してプラグインの機能を使用します。

コーディングのとき、プラグインから本体のアプリケーションで定義されたクラスを扱うには本体.exeファイルの参照を追加するだけでOKです。 本体のアプリケーションからプラグイン内のクラスを扱うときは、あらかじめ本体側で用意したinterfaceを実装したものに限るのが現実的。 各プラグイン共通のデータ構造を決めておきましょう。 それ以上のことをやりたい時はリフレクションでゴリゴリ、かなぁ?

2011年11月25日金曜日

wpf : UserControlを含んだクラスライブラリ(dll)の作成とデバッグ

wpfでUserControlを含んだクラスライブラリを作ったときのメモです。 最初は空プロジェクトにUserControlを追加してやってみたんですが、そのままではデバッグできませんでした。 デバッグ用に別プロジェクトでウィンドウを作って、そこでAssembly.LoadFrom → UserControlを貼り付けでデバッグしようとしたらUserControl内のコードでステップ実行ができませんでした。 困りますよね?

少々試行錯誤したところ、MainWindow付きの「wpfアプリケーション」でプロジェクトを作って、後で出力をクラスライブラリに変更する方法を発見。 作成&デバッグはMainWindowに貼り付けてやって、リリース時にdllを作る方法がわかりました。 これでUserControlのデバッグができます。 未確認ですが、カスタムコントロールとかを作るときにも同じようにできそうです。

2011年11月23日水曜日

C# : enum型の変数にint値を入れたときの中身

最初にC#について勉強したときに見たはずのことなんですけど、確認しようとして検索してもすぐにはヒットしなかったのでデバッガで見てみました。

enum TestEnum : int
{
    A = 3,
    B = 5,
    C
}

int t1 = 16;
int t2;
TestEnum t3;       // t3 : 0
t3 = TestEnum.A;   // t3 : A
t2 = (int)t3;      // t2 : 3
t3 = TestEnum.B;   // t3 : B
t2 = (int)t3;      // t2 : 5
t3 = TestEnum.C;   // t3 : C
t2 = (int)t3;      // t2 : 6
t3 = (TestEnum)t1; // t3 : 16
t2 = (int)t3;      // t2 : 16

enumの中身は、ただのintですよねぇ。 それだけ。 検索のキーワードがすぐに思いつかなくて、やってみた方が早いってことは多々ありますよね。

2011年11月22日火曜日

.net framework : フリーソフトの設定ファイルはどこに作るべきか

PCを買い換えてOSがWindowsXPからWindows7に変わったとき、program filesのアクセス権管理が厳格になったことに気付きました。 Vista以降で厳格になったようです。 それについて解説してあるページはいくつかあります。 たとえば、

セキュリティを考慮してこうなったようですね。

2011年11月20日日曜日

inkscapeでファイル保存ダイアログが開かない

たま~に使っているドローソフトのinkscape、いつのまにかファイル保存ダイアログが開かなくなっていました。 環境はこんな感じ。

  • Windows7 64bit home
  • inkscape 0.48.2 r9819
  • BUFFALO RAMDISK ユーティリティー Ver.3.0.0.0

1度保存してファイル名を付けてある画像の場合、上書き保存をするときに保存ダイアログは必要ありません。 そのため、上書き保存だけですんでいる間はこの不具合の影響はなし。 新規画像を作った後に保存しようとして気付きました。

2011年11月18日金曜日

.net framework : マウスカーソルの位置にあるウィンドウの情報を得る

前の投稿「wpf : マウスキャプチャとマウスカーソルの変更」の続きです。 コードは前の投稿のMainWindow.xaml.csを見てください。 ここでは「マウスキャプチャ中にマウスが指しているウィンドウの情報(タイトル、ウィンドウクラス、実行ファイル名)を得る」という部分について書きます。 前回書いたとおり躓きました。 「win32sdkの時代の定石コードを探してきてDllImportしてアレコレ」で済むかと思ってたんですが、64bitの壁に阻まれました。

サンプルコードを試した環境はwindows7 64bit版です。 で、その64bit環境で試したら、アプリケーションをx86(32bit)でビルドしたのとx64(64bit)でビルドしたのとで挙動が違ってました。

この部分のコードは次のような手順になっています。

  1. WindowFromPointでマウスが指しているウィンドウを探す。
  2. GetWindowTextでウィンドウのタイトルを得る。
  3. GetClassNameでウィンドウクラスを得る。
  4. プロセス操作で実行ファイル名を得る。

躓いたのは「1:WindowFromPoint」と「4:プロセス操作」です。 構成をx86(32bit)にして動作させると「4:プロセス操作」で64bitプロセスの実行ファイル名が得られませんでした。 構成をx64(64bit)にして動作させると「1:WindowFromPoint」が動いてくれませんでした。

2011年11月17日木曜日

wpf : マウスキャプチャとマウスカーソルの変更

wpfでマウスキャプチャをするサンプルプログラムを作ってみました。 キャプチャするには、

  • MouseLeftButtonDownなどのイベントでCaptureMouse。マウスカーソルをそれっぽいものに変更。
  • MouseLeftButtonUpなどのイベントでReleaseMouseCapture。そのときの座標で目的の処理をする。
  • キャプチャー終了時にLostMouseCaptureイベントが発行されるので、そこでマウスカーソルを戻す。

とやります。 LostMouseCaptureイベントはユーザーの操作でキャプチャーが終了したときも、他の原因(他のウィンドウがアクティブになるなど)でキャプチャーが終了したときにも発行されます。 キャプチャーの結果をもとに行いたい処理はMouseLeftButtonUpイベントのタイミングでやって、LostMouseCaptureイベントではマウスカーソルの切り替えだけ行います。 マウスカーソルの変更は、

mainWindow.Cursor = Cursors.なんたら;

です。 これだけ。

これだけでは何なので、

2011年11月11日金曜日

wpf : スクリーン座標はデバイス座標?

昨日の投稿では、マウスのグローバルフックとwin32sdkのWindowFromPointを使っています。 そのときちょっと気になってたのが座標変換です。

win32sdk上の座標は当然ながらデバイスピクセル単位、wpf上の座標は論理ピクセル単位になっています。 マウスフックの座標やWindowFromPointの座標はデバイスピクセル⇔論理ピクセルの座標変換をしないとズレてしまうはずなんですよね? ですが、昨日投稿したコードは座標変換なしで動いています。

「なにやら勘違いしていたらしい」ってことで、座標がどうなっているのか簡単に調べてみました。

2011年11月10日木曜日

wpf : 他のウィンドウを除外してヒットテスト

昨日の投稿、今読んだら日本語になってないところがあって訳分かりませんなぁ。 まぁ、書き直すのは面倒なのでコードを読んで察してください。 今回の投稿はその続きで、MainWindowの表示中の領域にマウスカーソルがある場合反応して、他のウィンドウの上にマウスカーソルがある場合除外するというヒットテストのコードを作成します。

昨日、「これやったら、もしかしたら他のウィンドウを除外できるかもしれないね?」ということで挙げた3点を試してみました。

  1. VisualTreeHelper.HitTestを使う。
  2. レンダリング領域やクリッピング領域のようなものが得られるメソッド/プロパティを探す。
  3. win32sdkのWindowFromPointを使ってカーソルが対象ウィンドウ上にあるか確かめる。

1はUIElement.InputHitTestと同じ動作でダメでした。 2のクリッピング領域も用途が違うらしくダメ、レンダリング領域の取得方法は検索で見つかりませんでした。 3のWindowFromPointは成功。 このやり方が最善なのかはわかりませんが、とりあえず3のやり方でヒットテストのコードを書いて整理してみました。

2011年11月9日水曜日

wpf : UIElement.InputHitTestを試したら予想と違った動作

ペンタブレットでペイントソフトを作ったときの事を空想して、wpfのヒットテストを試してみました。 使ったのはUIElement.InputHitTestです。

wpfのマウスイベントは基本的にイベントハンドラを登録したコントロール上にカーソルがあるとき発行されます。 しかしwintabでペンタブレットの入力処理をする場合、イベントにはそういう制限がありません。 アプリケーションがアクティブならカーソルがどこにあってもイベント(メッセージ)が発行されます。 アプリケーションがアクティブでなくても、場合によってはイベントが発行されます。 イベントハンドラで自分でヒットテストをして、対象のコントロール上にカーソルがあるか、イベントを処理するべきかを判断しなければなりません。 今回はそのヒットテスト部分だけ試作しました。

サンプルコードでペンタブを使ってコーディングミスをし、座標がズレてしまったら確認の意味がないので、今回はとりあえずマウスのグローバルフックで試しました。 何かのマウスイベントがあるたびにフックの中でHitTestをして、UIElement.InputHitTestがどのコントロールを返すのか確認します。 これで目的のコントロールを検出できるか確認。

2011年11月8日火曜日

アンケートが難しい時代

ニコニコ動画のネット世論調査を見ました。 なかなか偏った結果ですね。

ニコニコ動画にアクセスするのは若い世代に偏っていると言われています。 参加人数の関係からか、50代以上がひとまとめにされています。 少子高齢化の今、世論調査としての体をなしてないません。

じゃあマスメディアの世論調査はまともか?っていうとそんなことはないです。 未だに電話を使ったRDD方式とかやってるようですしね。 ずっと前から言われている

  • 個人情報保護法が施行されたあたりの時期から、「知らない人からの電話には出ない」人がいる。
  • 携帯しか持ってない人が調査対象に入っているのか不明。

っていう事柄への対策はどうなったんでしょう? 世論調査の電話に出る人は、知らない人からの電話に抵抗が少ない高齢者に偏ってそうです。

2011年11月7日月曜日

GeForce GTX 560とFirefoxの相性問題?解決せず

今使っているPC、Firefoxを使用中にモニタが数秒間真っ暗になる不具合をかかえています。 どうやらGeForce GTX 560とFirefoxの相性問題の模様。 「GeForceのベータ版ドライバ(285.27)でそれを解消できるかもしれない」とインストールしてもだめ。 ブラウザをFirefoxからGoogle Chromeに変更して様子を見ていました。

しばらくChromeを使っていたけど、こちらのブラウザを使っている間は同様の不具合はありませんでした。 これで、自分の中ではGeForceとFirefoxとの相性問題が原因ってことで確定に。

2011年11月4日金曜日

wpf : グローバルフックdllをC#から呼び出す

以前VC++で作った「グローバルフックでランダムな文字列を挿入するプログラム」をwpfでもやってみました。 目的は、

  • 64bit版のdll(VC++で作ったやつを流用)のロードを試す。
  • wpfでタスクトレイアプリの作成を試す。

の2点です。

そういえば、最初の投稿で「C#でのグローバルフックは色々と面倒くさそう」と書きましたが、ここを見るとそうでもないようですね。

dllを作るのとC#だけでやるのに手間の差はさほど無いようです。 けど、まぁいいや。

アプリケーションを起動するとタスクトレイにアイコンが表示されます。 その状態で別のアプリケーションを操作中にショートカットキー(デフォルトでCtrl+Alt+F)を押すとランダムな文字列が挿入されます。 ランダムな文字列は大文字小文字のアルファベットと数字です。 タスクトレイを右クリックすると設定、終了のメニューが出ます。 設定ダイアログはxamlで作成。 ショートカットキーと文字列の長さを変更可能。 「自分でも使うかどうか?」っていう機能を適当に実装しただけなので色々不親切になっています。

2011年11月2日水曜日

wpf : x64でxamlを編集するとデザイナがごねる

前に作った「グローバルフックでランダムな文字列を入力させるdll」、C#から呼び出すのを試してみました。 dllを無駄にx64で作ったのでwpfのテストコードの構成も無駄にx64に。 簡単なコードしか書いてないんですが、わけのわからないエラーが出ました。

エラーが出たのはdllを呼び出す部分ではなくxamlです。 曰く。

  • CLR 名前空間が定義されていません。'clr-namespace' URI が、アセンブリに含まれていない名前空間 'プロジェクト名' を参照しています。

clr-namespaceのまわりは以前作ったコードのコピー&ペーストだし、プロジェクトの名前空間を見つけられないなんていう状況がわかりません。 しばらく足止めをくらいました。

2011年11月1日火曜日

コードを投稿するときに使うサクラエディタのマクロ

ブログにxmlやプログラムのコードをそのまま載せると表示が崩れてしまいます。 崩れないようにするにはちょっとした変換が必要です。

  1. ちゃんと改行されるようにpreタグを使用。
  2. タブ文字をスペースに変換。
  3. &を実体参照で記述(&)
  4. <を実体参照で記述(&lt;)
  5. >を実体参照で記述(&gt;)

他のやり方もありますが、このブログではこんな感じでやっています。 タブ→スペースの変換はやらなくてもブラウザ側で対応されてますが、一応htmlの仕様らしいので変換。 実体参照を変換せずに投稿してもbloggerが変換してくれるっぽい(うろ覚え)ですが、一応自前で変換です。 順番を間違えると、投稿後の文字列の「<」と「>」が「&lt;」や「&gt;」になってしまうので注意。

この手順の変換はよくやるのでサクラエディタのマクロに登録してしまいました。 マクロのコードはコレです。

S_ReplaceAll("\t","    ",14);
S_ReplaceAll("&","&amp;",10);
S_ReplaceAll("<","&lt;",10);
S_ReplaceAll(">","&gt;",10);
S_ReDraw(0);

1回作っておくと便利ですね。

BBSによく投稿する人はタブ文字を全角空白にして、「&」、「<」、「>」を全角に変換するマクロとかを用意しておけば便利かもしれません。 ↑をちょっと替えればすぐ出来ます。