どちらもいわゆる「怪文書」に分類されるモノを扱ったサイト。「怪文書保存館」さんは主にネット上で収集される文書を,「異端図書館 (東京福袋)」さんはリアルで入手された文書を扱います。楽しいです。お世辞とか抜きで。
ところで怪文書保存館に投稿されている「私の通ってる高校は変だと思う」なんですが,やっぱり,その,この文書自身もアレなんですよね? 確かにかなり厳しい校風だとは思うし「携帯電話を勝手に使っちゃう」あたりは ( 事実だとすれば ) とんでもない話ではありますが,
なんと雨の日には自転車通学の人は雨合羽をしなくてはならないのです。
一体何を驚いているんだろう? 次のセンテンスで「傘 on 自転車の組み合わせで怒られる」と愚痴っていますが,・・・まさかっ!? ・・・というか,そのまさかなんですよね。これこそがこの文書が怪文書保存館に採用された理由です。
そういえば 2002-07-17 で紹介した「B-Files!」の特許文書もなかなかの怪文書風味。なるほど,いたるところに怪文書は落ちているものです・・・。
周波数:20MHz
2002-07-15で,複数行エディットボックスに文字列を追加する技を紹介しましたが,あのコードにはバグがあります。あれでは最終行の先頭に文字列が追加されてしまいます。正しいコードはこう。
// 文字列を追加,且つ,最後尾のラインに追随
void addStringEx(HWND edit_window, LPCTSTR str) {
int lidx = ::SendMessage(edit_window, EM_GETLINECOUNT, 0, 0);
// テキストがなくても 1 が返ります
int idx = ::SendMessage(edit_window, EM_LINEINDEX, lidx-1, 0);
if (idx < 0) return; // 追加には失敗しそう・・・
// これが必要
int pos = ::SendMessage(edit_window, EM_LINELENGTH, idx, 0);
::SendMessage(edit_window, EM_SETSEL, idx + pos, idx + pos);
::SendMessage(edit_window, EM_REPLACESEL, 0, (LPARAM)str);
}
EM_LINEINDEX で,最後尾の行の先頭の位置まで求めたのは正解でした。しかし詰めが甘かった模様。その行の末尾の位置を求めるために EM_LINELENGTH も必要です。
私はどんなコードで動作を検証していたのかというと,大体こんなの。
// button1 コントロールがクリックされた場合
LRESULT onButton1Click() {
// コントロールの文字列を複製 (メモリの解放が必要)
LPTSTR text = createWindowText(edit1);
// メモコントロールに文字列を追加
addStringEx(memo1, text);
addStringEx(memo1, "\r\n"); // 改行も追加
// 文字列バッファを開放
deleteWindowText(text);
return 0;
}
ここで edit1 は何の変哲もないエディットコントロール。createWindowText はウィンドウに関連付けられている文字列を,バッファを割り当てた上で複製します。deleteWindowText でバッファを開放。button1 ボタンがクリックされる度にこの関数が呼ばれるわけですが,
edit1 に何の変化も加えなければ,バグには気付きません。
よし,調子が出てきました。k|m たるもの こうでなくちゃ。
B-Files! / for all individual inventorz
数々の `ツボ' を押さえたまくった日本最強の爆笑公文書,それが「特許」! いつものように仕事中に読みふけってしまいました。この不良社会人め。
はっきり言って虚を突かれました。確かに「似非科学」の類はすンごく面白いんだよ,という事実は前々から睨んでいたんですが,そうかー,そういうのを集めたのが「特許」なんスよねー。B-Files はそれを収集,分類し,膨大なデータベースとして纏め上げています。
でもほら,今でこそ「珍発明」とか言われているものでも,将来,実は実現可能であった事が判ったりする可能性も・・ゼロじゃないものも・・中には・・あるかも知れないわけで・・・技術者として,何かを追い求めていく心はとても大事だと思いました。特許申請するだけならあまり人に迷惑かけないし。
そういえばアメリカかどこかで,「ブランコのこぎ方」で特許を取ったりしている人が登場したりして。曰く「金に汚い人間が特許をとってみんなが自由にブランコで遊べなくなる前に,自分で特許を取ってみんなの利益を保護する事にした」そうですが,むーん,物は言い様,ですかねー。
疲労度:15
・・・じゃないけど,ヘンな英語を集めたサイトを見つけたですよ。かなり有名であるという事実はこの際無視するとして。
タイトルのまんま,Japanese Engrish を集めたサイト。決して English ではないのでご注意。
似たようなコンセプトで・・・
我が日本国が誇る最強の Japanese Engrish "All your base are belong to us" にまつわるサイトです。この Engrish はあまりにも衝撃的だったため,海の向こうでは社会的現象にまで発展したらしいです。
もうなんていうか,大好きです。
制汗剤ってどないやねんね? 出すべきモノが出ないわけだからかなり非健康的な気がするんですが,でも大したトラブルも聞かないですもんね。こう暑いと 1 日 2 回はシャワーを浴びなくてはやってられませんが,うーん,制汗剤ねぇ・・。
前フリは意味不明ですが,中身はわりとマジ。今日紹介するのは複数行の EDIT コントロールへの文字列追加です。
パッと思いつくのはこんな方法。全部のコードを書くと長くなるんで,最小限肝心な関数だけを挙げています。
// 文字列を追加する関数?
// edit_window .. EDIT コントロールのウィンドウハンドル
// str .. 追加したい文字列
void addString(HWND edit_window, LPCTSTR str) {
int str_length = lstrlen(str);
int size = ::GetWindowTextLength(edit_window);
LPTSTR temp = ::GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT,
sizeof(TCHAR) * (size + str_length + 1));
size = ::GetWindowText(edit_window, temp, size+1 );
lstrcat(temp, str);
::SetWindowText( edit_window, temp );
::GlobalFree(temp);
}
GlobalAlloc() に GMEM_ZEROINIT を指定することで,確実に nil 終端であることを保証しています。ちょっとした工夫。
ただしこの関数では満足しません。文字列を追加するのにかなりのコストが掛かっていることと,文字列を追加するとコントロールに再描画が起こり,スクロールが一番上に戻ってしまうこと。それでも良い場合は構いませんが,今の私の目的とは異なっています。
私の目的は,文字列が追加されたら常に追加された文字列が見えるようにスクロールされていること。幸い,比較的簡単な方法がありました。
// 文字列を追加,且つ,最後尾のラインに追随
void addStringEx(HWND edit_window, LPCTSTR str) {
int lidx = ::SendMessage(edit_window, EM_GETLINECOUNT, 0, 0);
// テキストがなくても 1 が返ります
int idx = ::SendMessage(edit_window, EM_LINEINDEX, lidx-1, 0);
if (idx < 0) return; // 追加には失敗しそう・・・
::SendMessage(edit_window, EM_SETSEL, idx, idx);
::SendMessage(edit_window, EM_REPLACESEL, 0, (LPARAM)str);
}
なんと,行数が半分くらいになりました。・・・というか,すいません。FFFTP の EDIT コントロールを SPY++ で覗いただけなんです。同じような処理をしたい部分があったんで,つい・・・。
k|m はオープンソースな FFFTP を応援しています。いつまでも,いつまでも。
追記:このコードにはバグがあります。2002-07-18 参照ね。とほほ。
可愛げのないタイトルですが気にすんな。日々の雑記なんかこんなものです。というよりも,毎日更新するつもりなんかないのにどうして私は毎日雑記を更新してるんでしょうね。。。
今日・・じゃなくて実は先週あたりにハマったんですが,こんなコード。
// このコードはコンパイルできません
template<typename T>
class A {
public:
virtual const T method() = 0;
};
class B : public A<char *> {
public:
const char *method(){ return "B"; }
};
パッと見て「あぁ」と呟いた方,そう,あなたの考えは正しいのです。キーは B::method() の const の位置。
// これが正しいコードです・・
template<typename T>
class A {
public:
virtual const T method() = 0;
};
class B : public A<char *> {
public:
char * const method(){ return "B"; }
};
つまり B::method() の戻り値の型は const char * ではなく char * const になる,というのが正解。なんだかこの問題を理解することで,const 修飾子への理解も深まったかも知れません。
const char var と宣言した場合,固定されるのは var 自身が保持する値。似た感じで char * const var と宣言しても,var を変更するような演算は出来ません。それに比べて const char * var と宣言した場合,var は自由。固定されるのは var[0] や var[1] の値。ついでに const char * const var の場合は var も var[0] や var[1] も固定されます。これを踏まえて・・・
const T method() で固定されるのは method() の戻り値。T が int 型なら,const int が返ってくるわけです。T が char * な場合も同様に,method() の戻り値が自身が固定されなければなりません。だとすると必然的に const char * ではなく char * const が選ばれることになります。
C++ の複雑さの凄まじさは異常!
疲労度:226
Windows の GDI では,描画ツールとして主に「ペン」「ブラシ」「フォント」「背景色」「背景モード」「フォントの色」が用意されています。そのうち「背景色」「背景モード」「フォント」の色はいわゆる「GDI オブジェクトハンドル」は不要。前者「ペン」「ブラシ」「フォント」はそれぞれのハンドラが必要で,Create**** でハンドルを作り SelectObject で設定,使い終わったら SelectObject で元に戻して DeleteObject で解放してやります。このあたりをなんとか上手くやりくりすることで,ゲームを簡単に/高速に作る事が可能になります。
ただし決まりきったフォント等のハンドルをわざわざ CreateFont で生成するのは億劫なわけで,それは Windows が「ストックオブジェクト」を用意していました。CreateFont の代わりに GetStockObject を使うのです。DeleteObject は不要 ( 解放しても問題なし。MS もちゃんと分かってますねー )。
−−−−−ここまで基本−−−−−
GetStockObject は次のように使いますが
void viewFont( HWND some_window_handle ) {
HDC dc = ::GetDC( some_window_handle );
// DEFAULT_GUI_FONT は GUI で用いるデフォルトのフォント
HFONT font = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
HFONT old = (HFONT)::SelectObject(dc, font);
::TextOut(dc, 10, 10, "hello!" strlen("hello!"));
::SelectObject(dc, old);
//::DeleteObject(font); // 別にいらない
::ReleaseDC( some_window_handle, dc );
}
ここで一体どんなフォントで文字が描画されるのかを探ってみます。やり方は非常に簡単。
void viewFont( HWND some_window_handle ) {
HDC dc = ::GetDC( some_window_handle );
// DEFAULT_GUI_FONT は GUI で用いるデフォルトのフォント
HFONT font = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
HFONT old = (HFONT)::SelectObject(dc, font);
// ここからフォントの情報を取得
LOGFONT logfont;
::GetObject(font, sizeof(LOGFONT), &logfont);
::TextOut(dc, 10, 10, logfont.lfFaceName, strlen(logfont.lfFaceName));
::SelectObject(dc, old);
//::DeleteObject(font); // 別にいらない
::ReleaseDC( some_window_handle, dc );
}
これで指定したウィンドウにデフォルトの GUI 用フォント名が表示されます。多分ねー。
疲労度:0 !
本当に偶然の発見だったんですが・・何に使うのか分からない Mozilla の機能です。
まず,文字列を選択します。
コンテキストメニューを出せっ。
一番下,"view selection source" などと表示されています。選択すると・・・
いつの間にか随分と賢くなっちゃって・・・。しかし,何に使えるのかはちょっとボクよく分かりません。ちょっぴり大人の味のする機能でした。
疲労度:65
前々から仕事でプリンタを制御するアプリケーションを書いてますが,いよいよ昨日の夜から本格的に印刷を開始しました。そこで大問題が発生。
うまいこと印刷できちゃうよ!
何も問題なく,プログラム通り,私が考えていた通り,私が印刷したいモノがきちんと印刷されてくるのです。β版の納期まであと数日。いろんなところで潜んでいるはずの罠を早く見つけなければ,後々号泣するハメに陥ります。
開発方法を間違えたかもしれません。私も本格的に XP の勉強を始めるべきだと思った夏の夜は,台風の真っ只中でした。
排他制御を加えてブラクラチェッカーを復活させました。扱いづらくなったかも? とは言っても,普通の使い方さえしていれば,排他制御に引っかかってもきちんと復帰できるんですけどね。
疲労度:22
kチガイさんが 1 秒間に 5 回くらいリロードしてるですよ。前も同じような攻撃で coara さんに「勘弁してくれ (;´Д`)」て言われたんスよね。それでスクリプトを分割したり,coara さんの方に置いてあるスクリプトには排他制御を組み込んだりしたんだけど。。。一体何が楽しくてイタヅラしてますか (`Д´;)
あと,internet jah さんに送った詫び状が文字化けしてたらしくて鬱倍増。とほほのほー。。。
前回の続きです。なんとか IE の設定を変え,デフォルトで表示させるサイトを正常なものにすることで問題の解決を図ったのですが・・・
解決しなかったようだ。チャットの最中にも ( 他には何もしていないのに,突然? ) 別ウィンドウが開き,異常なサイトにアクセスしてしまう。どうすればよいだろうか。
( 実際にはもっと可愛げのある文体でした )
ぬ・・これはまさに,バックグラウンドで何かヤバいもの──まさに「ウィルス」と呼ばれるもの──が動いている予感。もしもそうだったならば,私に何が出来るかな。。。とりあえず,こんなプログラムを渡しました。
-> レジストリ内のデータを列挙するルーチン "regenum.c";
このプログラムは OS のバージョンや,OS 起動時に自動的に始まるアプリケーション ( ただしレジストリで覗けるもののみ ) を列挙します。同じディレクトリに _send_me.dat というテキストファイルが出来るので,それを送ってもらうのです。もっともプライバシー的にかなり問題があるわけで,そのへんを細かく説明しなければなりませんでした。まぁ背に腹はアレですもんね。
しかし実際に OS 起動時に自動的に実行されるアプリケーションは,レジストリに登録されているものばかりではありません。win.ini にも記述されているし「スタートアップ」フォルダにも置かれているし,何より私は「ドライバ」という存在の仕組みが全然分かっていません。もしこれで解決できなければ,私はより一層の研究が必要となります。いや,それよりも諦めて OS を再インストールしてもらおうかな。。。
返答はかなりの早さでした。そんな中でなんとなく香ばしそうなモノを発見。そのデータは "HKEY_LOCAL_MACHINE - Software - Microsoft - Windows - CurrentVersion - run - MSKernel32" とレジストリを辿った "C:\WINDOWS\SYSTEM\Winnn32.hta"。もう "プログラマの勘" 発動しまくりです。
Google で "Winnn32.hta" を検索。なんだかもの凄い状況になりました。異国情緒あふれるというか,なぜか英語のページに限って存在しません。ウィルスならば,それ系の何らかの英語サイトが検索されてもいいのに・・・。
かろうじて見つかっている「PC相談室」のキャッシュによると,なんだか分からないけど,これを無効にすることで解決したらしい? トロイだったのかも? しかし "WinNN32" というソフトウェアも同名のファイルを使うらしい? 歯切れの悪い結論ですが,とりあえず自動で起動しない手順を教えることにしました。
相手の OS が Windows98 であることは,先ほどのプログラムで分かっていました。そこで,次のようにして msconfig を起動:
PNG ファイル (4.4KBytes) ( このダイアログは無視してもらって )
"MSKernel32" 横のチェックボックスを外してもらいます。
そして顛末:
現在までのところ,特に問題は起きていないようだ。これで解決したかも知れない。
うん,それはよかったですね。しかし,おそらくワクチンメーカ各社とも把握していないらしい非常に怪しいファイルだったのです。本当にこれが正解なのかなあ・・?
そういえば,ふと思い出して "MSKernel32" で検索。・・・出てきました。以前流行した "VBS/LoverLetter.A" は,まさにレジストリ "HKEY_LOCAL_MACHINE - Software - Microsoft - Windows - CurrentVersion - run - MSKernel32" に巣くうワーム。こんな所にヘンな縁がありました。
件の見慣れない怪しいファイルと LoveLetter の間にどんな関係があったのか,今となってはもはや正確には知る術がないんですけどね。。。
うわー,歯切れが悪すぎ。。。
Google のキャッシュでかろうじて日本語サイトが見つかっていましたが,今確認したらキャッシュが更新されていました。Google さん,仕事してます・・・(泣)。