浦安市在住+デジカメ
浦安市在住のプログラマーが、デジカメを片手に日々を語ったり語らなかったり愚痴ったり・・・-
C#
Posted on 1月 22nd, 2006 はおりん No comments■ [program] 最近C#をはじめた。
はじめて4週間足らずだが、壁紙チェンジャーを作り始めた。
C#のキモは(C#に限らないが)、try-catch-finallyだと思った。
.NET FrameworkのAPI郡はほとんどエラーを返さない代わりに、例外をばんばん出してくる。
適切に処理しないと、C言語の系列のクセに、昔のVBよろしく、実行時エラーで落ちるわけだ。
■ あと、よくわからないのが、アプリの設定保存。
昔はINIファイルなり、レジストリなりに保存していたのだが、.NET以降はユーザーのApplicationDataにXMLで保存するのがデファクトらしい。
XMLって、どう作ってどう読むんだ?
なんか簡単なラッパークラスはないのか?
■ と、いうわけで、今回はとりあえずシリアライズしてみた。
さらに、TreeViewとTreeNodeを継承して、FileTreeとFileTreeNodeというコンポーネントを作っているので、その中身を保存したときのシリアライズのカスタマイズなんかも書いておこうと思う。
■ 以前、シリアライズといえば、データをバイナリなりテキストなりの羅列にしてファイルに放り込むものだったのだが、.NETのシリアライズはもうちょっと進化しており、各データに名前を付けられる。
つまり、バージョンアップなどで保存すべきデータが増えてしまっても、名前を付けたデータの中身さえ変わっていなければ、シリアル化したデータは引き継げるということだ。
また、クラス内部で独自のデータをシリアルストリームに加える際、クラス内部で付けた名前は、他のインスタンスとは区別される。
つまり、
シリアルストリーム
├Class1
│├val1
│└val2
└Class2
├val1
└val2というふうに、Class1とClass2という2つのインスタンスがあって、その両方をシリアル化した際、以前は順番を守ってシリアル化し、順番を守ってデシリアル化しないといけなかったのが、今度のシリアライズでは、名前をキーとしてデータを呼び出すので、順番は関係なし。しかも、Class1 のval1、Class2のval1というふうに、内部でちゃんと管理されているので、クラス内のメンバをシリアル化する時に、グローバルな固有名は考えず、クラス内だけの固有名を決めておけばよい、と。
これまたずいぶんと、オレ的にいえばこんな便利な設定保存方法はないじゃないかと思うのだが、いかがなものだろうか。
■ ただし、問題がないわけじゃない。
それはデシリアライズの順番で、たとえば、TreeViewは内部にTreeNodeのコレクションを持っているが、TreeViewを継承して、シリアライズ可能なSerializableTreeViewのクラスを作ったとしよう。
そこで、SerializableTreeViewのGetObjectメソッド(オブジェクトをシリアライズするときに自動的に呼ばれる。ここで、シリアライズストリームにデータを追加する)の中で、TreeNodeを1つずつシリアライズしていったとする。
すると、逆シリアル化の際には、まずSerializableTreeViewの逆シリアル化コンストラクタが呼ばれ、その後にTreeNodeの逆シリアル化コンストラクタが呼ばれる。
すると、どういう問題が起こるのかというと、TreeViewの逆シリアル化コンストラクタが呼ばれた時点で、内部のTreeNodeをコレクションに追加していくのが楽な手法だと思ったのだが、追加すべきTreeNodeのインスタンスがまだ作られていないので、コレクションに追加できない。
TreeNodeの逆シリアル化コンストラクタでは、追加すべきTreeViewのインスタンスがわからないので、自分自身を追加することが出来ない。
ということで、オレの場合は、仕方がないのでTreeViewを継承したクラスにシリアル化を行わせるのではなく、シリアル化を行う前に、TreeNodeの配列を作って、それを直接シリアライズした。
というわけで、シリアライズを行う際には、まず、シリアライズしたいデータのハッシュテーブルを作って、それぞれのデータに一意な名前を付け、そのハッシュテーブルをシリアル化すると良いと思った。
もっといい方法があるのかもしれん。
■ さて、せっかくの備忘録なので、カスタムクラスをシリアル化する手順でも。
まず、シリアル化したいクラスにSerializable属性を付ける。
そして、ISerializableインターフェースを継承する。
継承したら、実装するってことで、ISerializable.GetObjectDataメソッドを実装する。
GetObjectDataはシリアライズメソッドなので、デシリアライズも必要なので、デシリアライズコンストラクタも実装する。
というわけで出来上がったサンプルがコレ。
using System; using System.IO; using System.Runtime.Serialization; using System.Collections; namespace SerialTest { [Serializable] class SerialTestClass : ISerializable { public int val1; public string val2; SerialTest() { } SerialTest(SerializationInfo si, StreamingContext context) { this.val1 = si.GetInt32("val1"); this.val2 = si.GetString("val2"); } void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) { si.AddValue("val1", this.val1); si.AddValue("val1", this.val2); } } class SerialTest { public void Main() { SerialTestClass stc = new SerialTestClass(); stc.val1 = 10; stc.val2 = "Test"; try { FileStream fs = new FileStream("test.dat", FileMode.Create); Formatters.Binary.BinaryFormatter formatter = new Formatters.Binary.BinaryFormatter(); Hashtable data = new Hashtable(); data["stc"] = stc; formatter.Serialize(fs, data); } catch(IOException ioe) { ファイル関連の例外処理 } catch(SerializationException see) { シリアル化関連の例外 } finally { fs.Close(); } } } }
■ というわけで、AddValueとGet~~だけで、簡単にデータの保存と取出しが出来るという備忘録。
過去日記 -
暗号メール
Posted on 7月 21st, 2005 はおりん No comments■ 暗号メール、というと、スパイ映画などを連想される方も多々いらっしゃるだろう。
実際、スパイ映画や軍事モノの映画で、出来の良いものはほとんどの情報を暗号化して伝送している。
映画などではほとんど見られないが、一部、凝った造りのゲームなどでは現実の暗号化技術が使われているシーンも見受けられる。
■ 例を挙げると、Ubisoftが発売している、「SplinterCell」シリーズは、NSAのエージェント「サム・フィッシャー」が敵地、もしくは敵のいるところへ秘密裏に潜入し、作戦目標を達成するという、いわゆる「スニーキングミッション」型のゲームであるが(よくわからないひとは「メタルギア・ソリッド」の進化版だと思ってくれればよい)、作戦中に敵を倒したり、コンピュータを操作したりすると、電子メールが入手できたりする。
その電子メールなのだが、ゲーム中でも時として暗号化されていることがある。
第1作では暗号メールの中にところどころ平文があったりして、よくわからない、いかにもゲーム的な暗号化だったのだが、第2作では、本文を見る限り、おそらくPGPと思われる暗号化技術が使われており、暗号化パターンが英文字の大文字小文字の混ざり合った、ほぼ現実的で、一般的な暗号化技術が使用されていた。
どのゲームだったか忘れたが、どこかのゲームでは「PGPで暗号化しているから、少なくとも1日は解読できないだろう。」みたいな表現もあり、暗号化技術というものも、少しずつ世間に浸透してきたように思える。
■ しかしながら、いまのところ仕事でもプライベートでも、暗号メールというのを見たことがない。
何故、これほどまでに浸透しないのだろうか?
暗号化方式にはいくつかの種類があり、どれも敷居が高いようにも思える。
そこで提案したいのが、「公的個人認証」だ。
まだ完全に環境が整ってはいないが、おそらく、1~2年後には電子メールの暗号化の鍵として、公的個人認証サービスで発行される電子証明書がごく普通に利用できるようになるだろう。
現在は個人用の電子証明書は年間数千円以上かかり(会社にもよる)、無料のものがあるが、そちらは証明書の取得以外にも作業が必要で、証明書を送る相手にも、ちょっとした作業をしてもらわなければならない。
もちろん、自分で証明書を作ることも出来るが、こちらはさらに手間がかかり、システム管理者じゃないと運用するのは難しいだろう。
■ ちなみにMicrosoftが推進しているのはS/MIMEで、こちらはMSもAppleも概ね対応しているので利用が簡単だが、どの環境でも特に設定せずに署名に対応させるにはベリサインなどの信用されている認証機関の証明書を購入しなければならず、個人には敷居が高い。
その点PGPは無料だが、PGPに対応したシステムを構築しないと(簡単だが。)、暗号化されたメールが見られないし、暗号化したメールを送ることも出来ない。
■ 早いトコ公的個人認証サービスで電子メールが暗号化できるようになればよいのだが・・・
過去日記 -
メモリリーク
Posted on 2月 8th, 2005 はおりん No comments[program] Access Violation
オレのやり方が悪いのか、ベクタ側のバグなのか・・・
ベクタにvoid*、WPARAM、どちらを格納しても、push_backで不正アクセス。
STLをよく分かっておらん、というのもあるんだが・・・
うーん、MFCなら使い慣れてるんだがなぁ・・・
ど~も、イテレータというものになじめん。
まぁ、つまりは高度化されたテンプレートリストだから、イテレータは必要なのだが、なにかにつけてイテレータを要求するので、微妙に使い勝手が悪い。
自分の性にあったクラスでコーティングしてしまえばいいんだが、そのまえに、自分の組んだ部分でないコードでヒープ外にでてしまうんだから気持ち悪い。
ポインタを入れてはいけないんだろうか?
それとも、push_backの前になにかしなきゃならんのだろうか?う~む、わからん・・・
あきらめて本でも買うかなー、STLの。cout < < “あはははははは” << endl;
は便利だしなぁ・・・
そういや以前MFCのCStringも、長いこと使ってるとメモリリーク起こしやがったなぁ・・・
動的確保は難しいよ、うん■ [program] 動的メモリ確保をするときはMFCの方がいい
なにもMFCのCArrayがSTLより優れてるとか、CStringはUnicodeも扱えて便利なんだぞ!とか言っているわけではない。
オレが欲しいのはMFCのメモリ監視機能だ。
MFCの欠点として、まず上げられるのは、その独自性だ。
MFCに切り替えることで、プログラムの構造が大きく変わってしまう。
イヤがるひとも多いだろう。しかし!
慣れてしまえば、楽だし、そんなのはSDKも同じなので、まぁ、所詮は慣れである。
ではそうまでしてオレが欲しがる「メモリ監視」とはなんなのか。■ 動的メモリ確保を行っていて、一番問題となるのは、言うまでもなく確保したメモリの解放し忘れである。
サーバソフトウェアなんかでコレをやったら、一日とかからず物理メモリを食いつぶし、仮想メモリすら浸食していくだろう。
メモリを解放し忘れているのはすぐ分かる。
タスクマネージャを見れば、大量のメモリを食っていることが一目瞭然だからだ。
では、それが分かったプログラマーが次に吐く言葉といえばコレだろう。
「どこだ?」
連続稼働テストなんかをするくらいだ、コードは一通りチェックしているだろう。
大きなメモリを解放し忘れているならすぐ分かるだろう。
そんな大きなメモリを使用している箇所などそう多くはないはずだ。では、問題となるのは1回や2回の解放し忘れ程度では気付かないような、数十バイト、数百バイト程度の、いわゆる一時バッファの解放し忘れだ。
一時バッファなぞそこかしこで確保してるし、ポインタも大量にあって、チェックするには莫大な時間がかかる。
コードが大きくなってくればまさに不可能とも言いたくなるような状態だ。
そこで登場するのがMFCのメモリリーク検出構造体、CMemoryStateとなる。■ [program] CMemoryState
コレはいったい何なのか?
コレはクラスではなく、構造体だが、メンバだけでなくメソッドを持っており、クラスとどう違うのか甚だ疑問な構造体である。
この構造体はその名の通り、メモリ状態を保持する構造体だ。
ただし、そのメソッドによって、保持だけでなく、比較、検証まで出来るスグレモノなのだ。■ 実際に使ってみよう
CMemoryStateを利用するには、3つのオブジェクトインスタンスが必要だ。
1つ目は、チェック対象のコードを実行する前のメモリ状態を保存するインスタンス
2つ目は、メモリリークを検証するコード実行後のメモリ状態を取得、保存するインスタンス
3つ目は、上記2つのメモリ状態を比較し、結果を保存するインスタンス
以上3つのインスタンスを生成しておけば、メモリリークのチェックが出来る。実際には、確保した動的メモリが、解放されていなかったときにメモリリークとして検出される。
なお、「確保されていなくて当たり前~」と、自分では思っていても、それが当たり前かどうか、デバッガにはわからないので、それもメモリリークとして検出される。
必要なメモリは全部確保したあとに、検証コード実行前状態を取得するようにしよう。
具体的にはこう使う。#ifdef _DEBUG CMemoryState oldState, newState, chkMem; oldState.Checkpoint(); #endif 検証対象のコード #ifdef _DEBUG newState.Checkpoint(); if(chkMem.Difference(oldState, newState)) { chkMem.DumpStatistics(); } #endif
_DEBUGが定義してあるときだけ実行されるようにすれば、リリース版でパフォーマンス低下が起こるようなことはない。
これでメモリリークがあれば、なんらかのデバッグ表示があるはずだ。
VC++の出力ペインを表示しておくように。
さらに、「__LINE__」を使用して、行数なんかも出力しておくとさらにデバッグしやすいこと請け合いだ。
コレをバッファを使用しているようなところ付近に多数仕掛けておくと、時間とともにメモリを食いつぶすようなプログラムを書く可能性はぐっと低くなるはずだ。Windowsプログラマに一番多いミスはバッファの解放し忘れだと思う。
バッファを至る所に「作らされる」プログラムを書かざるをえないからだ。
この手法を使って、なるべく、メモリをキレイに使って欲しいものである。■ 以上、サルベージ
XPや2000などは、メモリリークを検出し、自動でコレクトしてくれるといわれているが、アレをあまり過信してはいけない。
なぜなら、アレは、プロセス終了時にコレクトしてくれるのであって、プロセスが動き続けている状態ではまったくコレクトしてくれないからだ。
クラスにはデストラクタがあるとはいえ、アレも所詮内部でfreeなどを呼んでいるに過ぎない。
CStringにNULL終端文字以外を入れていると頻繁にメモリリークを起こしてくれるのは、このへんに起因する。ハンドル関連も確か同じだったと思う。プロセス終了時には使用していたハンドルをことごとく解放してくれる(これはどうやらかなり信頼できるようだ。DLLでも使用していない限り、プロセス終了と同時に、ファイルロックもすべて解放された。)が、プロセスを終了しない限り、自力で解放しないと、どんどんとハンドルが増える。
過去日記
アレはカーネルDLL内にハンドルに関連付けた構造体を作っていることが多いので、思ったよりメモリを消費する。特にBMPハンドルや、DirectX系のハンドルなどは。 -
前々から日記のネタにしようと思っていたのだが。
Posted on 1月 22nd, 2005 はおりん No comments■バーチャルネット
腐男子, 過去日記
バーチャルネットアイドル、と言うでないですか。インターネット上で、バーチャルな人間を作り、アイドルにしてしまうというか、アイドルになってしまうアレですよ。そんなことを、友人と話していたら、突然、こんなメールを送ってきた。 続きを読む » -
リモートデスクトップ接続を許可するか、のレジストリエントリを編集する
Posted on 9月 23rd, 2004 はおりん No commentsさて、いきなり本題に触れると、リモートデスクトップを許可するかどうか、これはシステムのプロパティで設定する。
設定するということはどこかに記録されるということで、これは往々にしてレジストリである。
というわけで、探してみたところ、「HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control \Terminal Server」の中の
「fDenyTSConnections」というデータが、許可するかどうかのフラグであることがわかった。
直訳するなら、「マシン全体の設定⇒システム設定⇒現在の設定⇒システムのコントロール⇒ターミナルサーバーのコントロール
ターミナルサーバー接続を拒否するフラグ」となるだろう。
「ターミナルサーバー = リモートデスクトップ」であることは前述の通りだ。
あとは何らかの方法で外部からこのエントリを書き換えてやればよい。
Telnetできるならば、REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /d 0 /t REG_DWORD /f
(実際は一行)
で、Enterとすれば、フラグが0になる。
リモートレジストリで操作できるなら、REG ADD "\\対象のマシン名\HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /d 0 /t REG_DWORD /f
(実際は一行)
でも、同じことである。
どちらにしろ、ファイアーウォールを挟んでいないか、VPNを通しているなどの環境が必要になるので、やはり、忘れずに設定しておくのが一番であろう。ちなみに、この「REG」をいうコマンド、コマンドラインから、レジストリが操作できるので、バッチファイルに組み込むには最適である。
興味をそそられた自動化マニアは是非REG /?
の内容を読破してみよう。
過去日記
今までとはちょっと違ったレジストリが・・・見えて・・・くるか?