.NETアプリケーション


このページでは、私がヒマをみつけては、作った.NET Framework用のアプリケーションを公開します。
今後、ぼちぼち充実させていきますので、興味のある方は使ってみてください。
あと、プログラミングTipsなんかもちょこちょこ掲載していくつもりです。

プログラム名 解説
FullPathGetter ドラッグ&ドロップしたファイルをルールに従って加工します。
ソースカウンタ ドラッグ&ドロップしたファイルを拡張子に従って自動解析し、有効行数を計上するアプリケーションです。
設定により対応する言語を増やすことが出来ます。
XPMデータ変換 私がLinux Zaurusのプログラム開発で利用しているツールです。
256色までのドラッグ&ドロップした画像ファイルをQTopiaプログラミング等で利用可能なXPMデータに変換し、クリップボードに保存します。
そのまま、ソースに貼り付けてご利用下さい。
また、透過情報も変換されます。


C#はまりみち
このコーナーでは、私がC#を使っていてはまったことを独断と偏見によりTipsにまとめました。
自分で言うのも何ですが、お前ホントにシステム屋か?と存在を小一時間問い詰められそうな、おバカな「はまり」が多いです。
それでも、反面教師として少しでも何かの参考になれば幸いと思い恥ずかしながら公開します。(T=T)
カテゴリ はまり状況 リンク
GUI 画面の継承にはご注意 TIPS
デバッグ ブレークポイントが設定されない? TIPS
SOAP SOAPで引数にHashtableは使えない? TIPS?
SOAP SOAPに使ってはいけないメソッド名ってあるの? TIPS
GUI GetPixel/SetPixelって速くならないの? TIPS
[C#はまり道TOPに戻る]

GUI
画面の継承にはご注意
Visual Basic以降、統合開発環境によって画面の開発はずいぶんと楽になりました。
VS.NETでは、C#の画面デザインもVisual Basic同様楽チンにできてしまい、それはそれで非常にありがたいことだと思います。

さて、.NETはオブジェクト指向言語ですので、クラスを継承することが出来ます。

…てぇことは、同じような基本機能をもったフォームも継承して、開発生産性を向上したいなんて思うのも人情ってモンです。

VS.NETを使えば、ウィザードを使って楽々継承できるわけですが…。しかし?

私がある日、とある画面を継承し、それに統合開発環境で部品を追加していっていた時のことです。
その時私は、画面上の部品について、
(1).機能に関係のあるものは厳密に名前をつける
(2).機能に関係のない(デザインに過ぎない)ものには、統合開発環境の名づけるまま
といったルールで作成をしていました。

ところが実行してみると、継承元の画面に存在するはずの部品が消えているではありませんか!?

は?なんで?

…よくよく調べてみると、継承元の画面を作ったときに統合開発環境が自動で名づけた部品名と、今回追加して(統合開発環境が自動で名づけた)部品名が一致したため、部品が上書きされてしまった。 のが原因でした。

自動で名前つけてくれるのは良いけどさ、継承元がどんな部品をどんな名前で使ってるかぐらいちゃんと調べて名前付けてくれよ > VS.NETォォ??

とか思いましたが、そんな事言ってもしょうがないので心の叫びをぐっと飲み込むのでした(泣)

そもそも継承させようとするような画面は、名前の衝突を考慮したネーミングをしておくことが大事なんだとほんの少し反省した出来事でした
基本だよなぁ…(鬱)

[C#はまり道TOPに戻る]

デバッグ
ブレークポイントが設定されない?
VS.NETでデバッグしていると、時々、ブレークポイントが(?)と表示されてしまい、「現在の設定ではヒットしません」と表示されることがあります。
この現象は、デバッグシンボルが読込まれていないために発生します。
デバッグの出力ウィンドゥを見ていると〜.dllが読込まれました。シンボルは…といったメッセージが出ていますが、 ここで、シンボルは読込まれませんでしたと表示されているライブラリはデバッグシンボルが読込まれていません。
デバッグシンボルのファイルは、〜.pdbという拡張子を持ち、スタートアッププロジェクトのdebugフォルダの下にいます。

大抵は、リビルドすると再構成してくれますが、まれに、何の因果か、デバッグシンボルが全く更新されなくなり、呪われたかとしか思えない、狂ったデバッグ状況になることがあります。

そんなときは、リビルドしても〜.pdbファイルの日付が更新されていないことを確認し、以下の手順で対応すればOKみたいです。

(1).シンボルが正しく更新されていないプロジェクトのプロパティ->構成プロパティ->ビルドの中にDEBUG情報の生成項目を一旦Falseにする。
#うまくヒットしないライブラリのプロジェクトなどがあやしい。

(2).当該プロジェクトをビルドする。

(3).(1)の項目をTrueに変更し、リビルドする。

(4).デバッグシンボルの日付が更新されるとOK!

デバッガを信頼しすぎて、丸一日を無駄につぶした経験からのTipsでした。(泣)

[C#はまり道TOPに戻る]

SOAP
SOAPで引数にHashtableは使えない?
C#のクラスライブラリに、Hashtable(System.Collections.Hashtable)があります。
これは、オブジェクトをキーワードと関連付けて格納しておけるクラスで、使いようによっては非常に役立つクラスです。
以前、SOAPを利用したAPサービスで、キーワードと引数で、SOAP通信の入り口を簡略化してしまおうと考えたことがあります。

その引数に、なんでもほうり込めるクラスHashtableを使おうとしました。

これ、コンパイルは無事通りますが、実行!とすると…。実行時エラーで落ちます!
どうやら、Hashtableが実装しているIDictionaryインタフェースがSOAPに対応していないのが原因らしいです。

残念!

[C#はまり道TOPに戻る]

SOAP
SOAPに使ってはいけないメソッド名ってあるの?
VS.NETでは、割と簡単にSOAP Webサービスが作れちゃいます。
開発している段階では、特に何の問題もないように思えますが、実は使ってはならないメソッド名があります。
何でもいいから、Web参照を使うプロジェクトを作ってみて、クラスビューを覗いてみると、System.Web.Services.Protocols.SoapHttpClientProtocolを 継承したクラスが自動生成されているのが分かると思います。

このクラス、SOAPのWDSLを読込んで自動生成されるのですが…、この時、クラスビューでベースとインターフェイスに含まれるメソッドと 同じ名前で、引数の型も同じメソッドを定義しているとはまります。
え?そんなことってあるの?あっても確率低いでしょ?と、思われるかもしれません。

…たしかにそうかもしれませんが…。
私は、一番最初に作ったWebサービスで、object[] Invoke(string, object[])というメソッドを作ってしまい、みごとにはまりました。(泣)

なんでそんなことになったかというと…
SOAPで沢山の種類のWebサービスを提供しなくてはならないことが分かっているAPで、
(1).Facadeパターンっぽく窓口を一つにしてしまえ
(2).リクエスト文字列でサービスを指定して、引数はobject[]、戻り値はobject[]がいいね。
(3).メソッド名は…、こういうもんだからやっぱInvokeでしょ?

…と考えたのですが、こやつが奇しくも自動生成のメソッドとかぶってしまい、ちょうどoverrideされた形になったわけです。(^^;
実行すると当然の事ながら上手く動かない!
な・ん・で・だぁ〜!?と思って色々調べてようやく判明した次第。

自動生成って…、つくづく、プログラマをアホにする機能だなぁ…と実感させられたのでした。

[C#はまり道TOPに戻る]

GUI
GetPixel/SetPixelって速くならないの?
画像処理のプログラミングをしているとどうしても、1ピクセルにアクセスしたいときがあります。
.NETで画像イメージを保存するクラスは、Bitmapクラスです。 このクラスで1ピクセルにアクセスする場合は、GetPixel(x, y)/SetPixel(x, y, color)を使うと簡単にアクセスすることができます。
しかし、使ってみた人はわかると思いますがこの命令、どうかと思うくらい遅いです。
ばかでかい画像なんかをこの命令で処理していたら、日が暮れます。

なんとか速くする方法はないのでしょうか?

実は、10倍くらい速くなる方法があります。
ただし、この方法はポインタを使うため、unsafeとなるため使用には十分な注意が必要です。

それでは、その方法を記述してみます。
Bitmapクラスには、LockBitsという命令があります。これは、Bitmapクラスが内部にもつ画像情報にアクセスできるようにする怪しい命令です。
この命令はBitmapDataというクラスを返すのですが、この中のScan0というプロパティが画像情報の先頭アドレスを表しています。
要するに、Scan0の値をポインタとすれば、直接画像情報にアクセスできるということですね。
Scan0をポインタにするには、どうすれば良いのでしょうか?
その例を以下に示します。

Bitmap bmp = new Bitmap(320, 100); BitmapData img; //--------------------------------------------- // 直接アクセス開始 //--------------------------------------------- public void BeginAccess() { img = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); } //--------------------------------------------- //GetPixcel(x, y)の例 //--------------------------------------------- public Color GetPixel(int x, int y) { unsafe { byte* adr = (byte*)img.Scan0; //アドレス計算 int pos = x * 3 + img.Stride * y; //レンジチェックはとりあえずなし byte b = adr[pos + 0]; byte g = adr[pos + 1]; byte r = adr[pos + 2]; return Color.FromArgb(r, g, b); } } //--------------------------------------------- //SetPixcel(x, y, col);の例 //--------------------------------------------- void SetPixel(int x, int y, Color col) { unsafe { byte* adr = (byte*)img.Scan0; //アドレス計算 int pos = x * 3 + img.Stride * y; //レンジチェックはとりあえずなし adr[pos + 0] = col.B; adr[pos + 1] = col.G; adr[pos + 2] = col.R; } } //--------------------------------------------- // 直接アクセス終了 //--------------------------------------------- public void EndAccess() { bmp.UnlockBits(img); } さて、この例のミソは、BeginAccessで、BitmapData imgを取得するときに、第3引数にPixelFormat.Format24bppRgbを使用している点です。
これは、1ピクセルを24bitのRGBで表すという意味で、つまり、先頭から1バイトずつR,G,BB,G,Rの順で直線に並んでいます。
このデータにアクセスするには、Scan0が示す番地から、始まるポインタを宣言してやればよいため、例では、
byte* adr = (byte*)img.Scan0;
とバイトポインタへ置き換えを行い、その後で
int pos = x * 3 + bmp.Width * 3 * y;int pos = x * 3 + img.Stride * y;
と、x, y座標の先頭バイトの位置を計算しています。
しかし、byte*はポインタであるため、これを使用した.NETプロジェクトはunsafeとなってしまい、/unsafeオプションを指定してコンパイルしなくてはなりません。
いわゆるマネージドではなくなりますが、その分目に見えるほど高速化されるので、速度に悩む方はお試しになってはいかがでしょうか?

ちなみに、私は将来BitmapのGetPixel/SetPixelメソッドが高速化されても移行しやすいように、Bitmapのラッパークラスを作り、Bitmapと同様のメソッドで扱えるようにしています。
使用するBitmapのメソッドをラップしているので、扱いがほぼ同じとなり非常に便利に使えています。

[C#はまり道TOPに戻る]