主にVisual Basic .NETについてのメモ書きです。 関連するWindows関係のメモも残していきます。 |
2003年2月12日 2:01:44
FETCHコマンドとメールヘッダーの日本語デコード処理が完成。 デコード処理はいろんな例外パターンを想定する必要があって、かなりややこしい文字列処理をしたのだけど、いろんなパターンのテストケースを作ってNunitでテストしながら、コーディングしたので、たぶん問題ないでしょう。 あと、暫定でメールの一覧表示画面も作って、表示させることまでできました。 次こそ、設定の保存や、タイマー処理などのユーザーが見える部分を作っていきます。 メールのアドレスや件名などによるフィルタリング機能は、一通り基本の機能がそろってから作成かな? ・・・といっても、Javaで作ったときもここまでは出来てたんだよなぁ・・・まあ、作りは格段に今の方が良くできてるけどね。 |
2003年2月11日 17:25:54
2.0になってテストケースの書き方が変わっているので、ここでチェック http://www.divakk.co.jp/aoyagi/csharp_tips_nunit.html |
2003年2月10日 1:05:28
一応、進捗報告→誰に?(笑) とりあえずメールチェッカーが使うIMAPコマンドはFETCH以外実装完了。FETCHもあと少しの作業で完成。 サーバーからオクテットが指定された返答が来た場合の処理がうまくいってるかはまだわかりませぬ(汗) この部分が完成すれば技術的な課題はとりあえずクリアなはず。 あとは、どういう画面のインターフェースにするかです。これが一番大変な気もするけどね・・・ |
2003年1月27日 2:03:51
さっぱり、わけわからなくなってしまって、スレッドを使用するのはやめることにしました。 非同期で受信処理をさせていましたが、そうすると受信したデータを元に何かするときに、すでに受信されたのかどうかのチェックをする必要が出てくるし、なんやかんやで収集がつかなくなりました(T.T) できることならスレッドは使わずに、どうしても使わなくてはいけない場合は複雑なことはさせないというのが、必勝パターンのような気がします(^_^) ちゅーことで、スレッド使わずに必要な分だけレシーブするように変えたら、いやーめちゃくちゃプログラムのすすみが早いです。 スレッド使わないようにしてから、接続からログイン、未読のメールのIDを取得するまで二時間程度でできちゃいました(笑) 最初から背伸びせずに簡単な方法でやるべきだったようです。 「IMAPは常にデータを受信できるようにしておく必要がある」とのことでしたが、考えてみればバッファにはたまるわけですから、別にスレッドにする必要もないんです。 これで、ささーっと作ってしまうぞ!! |
2003年1月26日 15:08:34
基本的なことなんで、いまさらそんなことも理解していなかったのか!!という感じなんですが・・・ Java と一緒で .NET の変数には値型と参照型の二つの変数があります。 値型は Integer や Long などで、変数を作成したメモリに直接値が書き込まれています(表現が合ってるかな?(笑))。 一方参照型は、オブジェクトです。String も .NET ではオブジェクトになります。これらの参照型の変数は変数自体のメモリ領域には実際の値は入っておらず、別の実際の値が書き込まれているメモリのアドレスが書き込まれています。ようは C でいうポインタです。 ここまでは良いとして、参照型の変数をメソッドの引数や他の変数へ代入した場合にどうなるかが少し曖昧だったのです。 たとえば、変数Aは参照型の変数で、これを別の変数Bに入れようとした場合に渡される参照は、Aに入っている参照なのか、それともA自身への参照なのか? それで、実験してみました。
10行目と18行目で que オブジェクトをそれぞれ代入していますが、もしこの代入で que の中の参照が渡されずに、 que 変数自体の参照が渡されているならば、 que1 と que2 は同じ内容を指すことになるので
でも、実際は12行目で New で新しいオブジェクトを que に与えていますが、 que1 には値がちゃんと残ったままになっています。 つまり、代入は参照を渡すと言うよりも、参照の値渡しをしているということになります。 結局、変数の中身が値型であろと参照型であろうと、代入(と、たぶん引数で与えた場合も)は変数の中身を値渡ししているということになります(たぶんね・・・) ※結局、Javaと一緒なわけで変数のポインタを渡すことは出来ないということですね。このあたりでもいろいろ説明されてました。 |
前にStreamReader.ReadLineメソッドが、受信バッファに何も無いときに実行すると、ずっと処理が戻ってこないので、他のスレッドで受信待ちの状態にしておくと良いかもというアイディアをここに書いていたが、どうもそれもうまくいかないようです。 問題が起きたのはアプリケーションの終了時。この別スレッドで動いている受信待ちクラスが終了してくれずに、画面上は終わってるように見えてもプログラム自体はメモリに残ったままになってしまったのです。 Ctrl + Breakで止めてみると、やはりReadlineで止まってるぅー(T.T) Threading.Abortメソッドを使っても、なぜか終了しないし。 (おそらく、Readlineの処理が終わって安全に終了できる状態になって止まるのでしょう) むりやり、StreamReaderをCloseすればエラーで終了するのだが、それではあんまり。 (というか、受信を別スレッドでやること自体あんまりだったのか?!) だが結局、やりたくなかったが、終了時のみエラーを無視して強制的に終了するようにして対処した(裏でエラーは起きているが画面に出ないだけ)。 他の方策としてはタイムアウト時間を短く指定すれば、タイムアウトで終了するので、その時のエラーをとばすとかすると、少しはエレガントかも。 スレッドを使わずに、順次必要な分だけReadしていっても良さそうなんだが、あちこちの文献に「IMAPクライアントはいつでもサーバーのデータを受信出来る必要がある」というのが、気になって変えるのもなんだかという感じ。 いろいろ調べてみても、その「いつでも受信できるようにする」必要があるコマンドがわからないんで、本当にそうすべきなのかちょっとわからないのだけど。 外国のサンプルとかを見てみるが、やはり必要回数分しかReadlineを実行しないサンプルしか見あたらなかった。別の手法では上にあげたタイムアウト時間を短くして対処する方法があった。この二つしか選択肢はないんだろうかねぇ。 |
2003年1月18日 12:30:09
ファイルを作成しようと思ってヘルプを探すが、FileクラスはUTF-8での書き出ししかしないように出来ている。 MSはたぶんUTF-8を推奨しているのだろうが、自分が使ってるテキストエディタの秀丸くんは、何も指定せずにテキストを開くとShift-JISで開いてしまうようだ。 (XPについているメモ帳はちゃんとUTF-8で開くんだよな) でも、Win98ユーザーとかは文字化けしたりするだろうから、やはりShift-JISで書きたい。 で、探したところ http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet08/vb6tonet08_02.html にありました。さすが@IT。 StreamWriterクラスからもファイル作成できるんだね。調べが足りなかった。 |
2003年1月17日 0:26:15
うーん、.NETはまだちゃんと使えてないなー。 今日、思わず以下のようなコードを書いてどつぼにはまった
よく見てみると、「PortNumber() As Integer」と書くところを「PortNumber(ByVal port As Integer) As Integer」としている。 こんな構文あるのか?(笑) プロパティー名の後に引数みたいなのがセットできるみたいだが・・・ということでMSDNを見ると 「これによりプロパティのシグネチャが識別されます」とある。 シグネチャ、つまりメソッドの名前と引数の組み合わせのことだね。 シグネチャが違うと言えば、オーバーロードを連想した。オーバーロードはメソッドの名前が同じでも別のメソッドとして扱われるという仕組みのこと。 確かに、ここの引数を変えると同じ名前でプロパティーが登録できた。うーん。 最初に間違って書いた方も
どういうときに使うんだ、これ?(笑) |
今まで、エラー処理はその時々考えついた方法でやっていて、定石みたいなのを見つけ切れていなかったので、なかなか迷って先に進めなかった。 |
2003年1月15日 1:05:26
電子メールプロトコルの本や、MSDNと戦いやっと方法がわかりました。 EncodingクラスでgetDecoderを使うのはわかったけど、「Encoding.(どっと)」と打っても、ASCIIやUnicodeしか出ない(T_T) getEncoding("ISO-2022")でもだめ。 インターネットをさまようこと一時間。ありました。 http://www.atmarkit.co.jp/fdotnet/vb6tonet/vb6tonet08/vb6tonet08_02.html おしい!。正しくはISO-2022-JPだった。これで無事、メールのヘッダーをデコードして日本語表示できた。 サンプルを載せておく。 フォームにはテキストボックスを二つつけて、Text1にデコード前の文字列を貼り付けて、このメソッドを実行すると、Text2にデコードした内容が表示される。
|
.NET のクラスライブラリがやってくれるから、気にしなくてもいいけど、知っておくと上のソースが何しているかわかるだろうし、他のエンコーディングの時もイメージつかみやすいかも。 base64 エンコードとは、ぶっちゃけて言えば、バイナリデータを 7bit ASCII (文字列)で表せる形に変換する仕組みの一つのこと。 メールは基本的にテキストしか扱えないので、こういう仕組みを使って、バイナリデータを扱えるようにしている。 どういう変換をしているかというと、まずバイナリデータ6ビットずつで区切り、それ四つで一つの固まりとして扱う。 6ビットは10進数で言うと0から63の数字まで表せる。この0から63をそれぞれA-Z,a-z,+,/の文字列に割り当てて表現することで、 ASCII 文字だけでバイナリデータを表現することが出来る(ちなみにAは0、小文字iは34を表す) 当然元々8ビットのデータを6ビットで区切り直すと、あまりが出たりするので、そのぶんは=で帳尻を合わせる。 だいたい、こんな感じだと思う。 今回のメールチェッカーではこれの逆のデコード作業を行うわけです。 |
2003年1月13日 23:34:50
結局正月何もやらずに全く進んでないメールチェッカーだが、とりあえずソケットで接続して、IMAP サーバーとメッセージのやりとりをしながらだいたい方向がつかめてきた。 「もしかして二時間ぐらいで出来るんじゃ?」と思って、ガーっと今やってます。 で、一つの山にさしかかりました(笑) そう、日本語ヘッダのデコードです。と思ってGoogleで調べてみたら、いいとこ見つかりました。 http://tokyo.cool.ne.jp/taquino/mailreader/dehead.shtml まさに俺が求めていた情報。RFCをまず調べるのが王道なんだろうが、めんどいし(笑) でも、やっぱBase64とか出てくるのか。名前しかしらんぞ(T.T) |
2003年1月13日 10:38:33
最近思ったのだが、なぜプロパティーの名前とSetの所両方に同じ型を書かなくてはいけないのか? 必ず一緒にする必要があるなら、片方だけでいいのでは? 継承とか、もしかすると関係するのかなー? Property StartKojSEQ() As Integer Get Return mStartKojSEQ End Get Set(ByVal Value As Integer) mStartKojSEQ = Value End Set End Property |
2003年1月5日 16:37:41
ソケット通信でこのメソッドを実行してみたが、バッファ(?)に何も入ってきていない場合は、ずっと(?)通信待ち(だと思うが)の状態になり、プログラムはそこでストップしてしまう。 たとえば、何回かこのメソッドを実行しあちらから送信してきたデータをすべて読み込んだのに、さらにこのメソッドを実行したりした場合だ。 ドキュメントを見ると、「入力ストリームの末尾に到達した場合、戻り値は null 参照 (Visual Basic では Nothing) です。」とあるので、てっきりバッファ内のデータをすべて読み終えたらNothingが返ってくると思っていたのだが、どうやらそういう意味ではないようだ(ファイルの読み込みの時はファイルの最後まで来たらNothingが返ってくるのかも?!) まあ、こういう動きだとわかればそのように作ればいいだけで、必要回数だけこのメソッドを呼び出すか、一度考えついたように、別スレッドでひたすら受信待ちさせておけば、ReadLineでプログラムがストップすることは無いだろう。 |