何気にリニューアルしてみました。どこが変わったのか,分かった人には金一封。嘘です。実はただ xml 宣言とドキュメント宣言を記述してみただけでした。
今までこの文書はただのプレーンテキストとも HTML 文書とも言えない,なんだか分からない位置付けだったわけです。とはいうもののなんとなく ( 個人の好みで ) xhtml 文書風味にはしているわけですが,最大の問題点:
xml 宣言内に encoding 属性が必須!!
Unicode で編集したりしているわけではないため,encoding 属性にて文字コードを指定しなければなりません。ローカルでは Shift_JIS で保存/編集しているので encoding="Shift_JIS" と書くべき? じゃないと,ローカルのファイルをブラウザで確認できませんもんね。しかしネット上にアップロードする時は EUC-JP に変換しているので encoding="EUC-JP" と記述されていなければなりません。この部分の文字列を自動で置換してくれる FTP ソフトがあればいいんだけど,自分で作るしかないのかな・・・
今回,私が採用した解決法は「ローカルでも EUC-JP で保存/編集」でした。今までは Shift_JIS しか扱えないエディタで雑記を書いていましたが,ここで一気に「サクラエディタ」に移行。かなり便利になりましたとさ。
ちなみに「サクラエディタ」は sourceforge.net で活動が行われているオープンソースなソフトウェア。そのソースコードの量たるや,さすがにハンパじゃありませんでした。読破は難しそうです・・・
疲労度:0
謎ってほどでもないんだけど,ちょっと笑ったかもしれないネタです。
WINSOCK2.H / 476 行目にて,Address Family として AF_ISO と同じ値で AF_OSI が定義されているのを見つけました。OSI って何っ。アンチ ISO の人が使いたがる値? 軽く調べてみたところ,OSI の正体は "Open Systems Interconnection" だとか。プロトコル名 "TP4/CLNS","TP4/NULL" または "forth" と呼ばれているという情報を得ました。
それはともかく,少なくとも私は一生使わないと思います。hehehe...
これも謎。WINSOCK2.H / 489 行目です。
#define AF_UNKNOWN1 20 /* Somebody is using this! */
「誰か使ってるし!」てキミ・・・誰がよっ!?
ネット上で検索した限り,この Address Family については何も調べがつきませんでした。何らかの立派な本が必要? ですか?
AF_OSI ]ついでなので,少なくとも VC++5.0 の WINSOCK2.H に定義されていなかった Address Family を列挙してみます。でもそれぞれの意味についてはやっぱり調べられませんでした。特定のシステムのみがローカルな目的で使うものだったりして?
#define AF_LOCAL AF_UNIX /* AF_UNIX と同じ意味 */
#define AF_CLUSTER 24 /* Microsoft Wolfpack */
#define AF_12844 25 /* IEEE 1284.4 WG AF */
#define AF_IRDA 26 /* IrDA */
#define AF_NETDES 28
#define AF_TCNPROCESS 29
#define AF_TCNMESSAGE 30
#define AF_ICLFXBM 31
27 が抜け落ちてるのが気になるなー。なお,AF_MAX はどうも Addres Family で指定できる最大値 + 1 を定義するような気がするんですよね。ということで,
#ifdef AF_MAX
# undef AF_MAX
#endif
#define AF_MAX 32
おし,こんなもんっすか。・・・しかし肝心の winsock.dll 様はこれらの Address Family をサポートしていない可能性があるという罠・・・
終わったかに見えた "前の仕事" ですが,お客様のサーバやマシンに,今回私たちが作ったアプリケーションをインストールする作業も任されてしまいました。つまり私が書いたインストールマニュアルは不要ってわけですか。せっかく気合入れて書いたのに・・・。
使用した DB は PostgreSQL。ODBC にも挑戦したし,なんとなく DB というモノ自体に慣れた感じがします。
実際にテスト用のテーブルを作成しようとしたわけですが・・・作れませんでした。具体的なエラーメッセージは忘れたんだけど,パースエラーだったかな?
原因は timestamp without time zone 型。運の悪いことに,私が使っていた PostgreSQL のバージョンは 7.1 でした。しかし timestamp without time zone 型をサポートするのはバージョン 7.2 以降。バージョンが小数点以下の部分しか違っていないのに,まさか型のサポート状況が違っているとは思いませんでした。とほほ。
今日は時間も遅くなったので,ちょっとしたメモということで雑記終了〜。
疲労度:596287
体中アルコールのにおいが染み付いている気がしてブルーな秋晴れの日。ちなみに昨晩は救急車を 2 回も呼ぶ騒ぎに発展,そして 2 回とも「暴れすぎて診察不可能」と結論。救急隊員のおいさん曰く
「最後の手段で,警察に引き取ってもらうってのもアリだけどどうよ?」
・・マジらしいのでビビりました。
パトカーよりも先にタクシーがつかまったので,そのまま会社に運んで夜を明かしたわけです。今日,結局本人は会社を休んじゃいました。あたりまえですわ。。。
さて今日はソケットのネタ。例えば自分が何らかのサーバを建てるとして,接続して来た人の IP アドレスは accept() の第 2 引数に渡した sockaddr 構造体 ( もしくは,特に sockaddr_in 構造体 ) から取得が可能です。しかしサーバ自身の IP アドレスは誰が教えてくれるんだろう? 確認くんのようなサービスから教えてもらうのかなあ? いや,そういうのはなんとなくマヌケな気がします。
自前でインターネットに接続している人たちにとって,IP アドレスは自明なものなんですよね? 自前で「インターネット」というコミュニティに接続するにはルータだとか何だとか特殊な機器が必要で,そういった機器に IP アドレスが割り当てられている・・んですよね? その取扱説明書に IP アドレスか何かが書いてあるのでしょう ( 間違ってるかも知れませんが,今は重要でもありません )。
しかしダイアルアパーの人にとって,IP アドレスとはプロバイダさんがその都度自動で割り当ててくれるもの。私たちダイアルアパーは知ったこっちゃないというスタンスをとる以外にありません。
そんな IP アドレスをどうやって取得すればいいんだろう? ということで,こんなコードを見つけました。
->自分の IP アドレスを表示するルーチン ipaddr.cpp;
使用する主な関数は gethostname() と gethostbyname()。Windows では gethostname() の代わりに ::GetComputerName() でもよいようです。
このルーチンでは gethostbuaddr() 後で hostent::h_name に入っているらしい FQDN も表示している・・はずなんですが,私の環境では ::GetLastError() で 11004 = WSANO_DATA が起こります。なんじゃーそりゃー。
疲労度:859
新人さんが来たという事で「新人歓迎会」なるものが催されましたが,某社長に煽られて強い酒を大量にイッキのみしちゃうヤシが発生。案の定,メチャクチャによぱらいました。一人で静かにケロケロしててくれるならまだましなんだけど,しかし彼はリバースにまみれて所狭しと暴れまくり,まさしくグロテスク・ヴァイヲレンス・アクション! 暴れる彼を取り押さえ,( 飲み屋は会社の近くだったわけですが ) 会社まで連れ帰って容態は安定した模様。後はそのヨパライの戯言に付き合い,なんとか酔いが覚めたところで「おつかれさまー」てなもんですか。家に帰ったのは午前 4 時ぃ!
というわけで,今日の雑記には日記という形で終わりです,いじょ。
疲労度:493573245698
フォント列挙の挙動がいまいち謎なまま何の有効なリソースも得られないので,気分転換にソケットをいじくろうと思いました。そういえば connect() にタイムアウトを設定することはできないのかな? 多くの場合 connect() はほぼ一瞬にして終わってしまうため,あんましタイムアウト処理を実現しているコードを見る事はありません。
Programming UNIX Socket FAQ in Japanese というリソースを紐といてみると,「6. 高度なソケットプログラミング」にズバリ正解が書いてありました。そこで書いてみたのがこんなコード:
->connect() タイムアウト処理実験用コード "conn1.cpp";
ポート番号 80 に connect() できるようなドメイン名もしくは IP アドレスを引数に渡してやると,実際に connect() に成功するまでのミリ秒を計測します。ちなみに inet_aton() 関数は Perl のパクリです。笑い
それでは実験。HTTP サーバを建てずに 127.0.0.1 に connect() してみます。前述の Socket FAQ を要約すると,connect() に失敗すると select() は上記のコードでは 1 を返し,そして getsockopt() でエラーを示す値を返してくれるはずです。
・・・つか,だめでした。いつまで待っても select() を行っているループから抜けません。すなわち select() がずっと 0 を返してくるばかりなのです。
もっとも,UNIX の各種ライブラリの扱い方と,それと互換性を持たせた ( はずの ) Windows の API の扱い方がほんのわずかに異なるのは覚悟の上。聞いたところでは,例えば Windows ではただの時間待ちの目的で select() を使うことはできません。きちんと有効なファイルディスクリプタを設定していないと,正常に動かないらしいのです。これはもうこいうモノだと理解しておくしか無いっすかね。無いっすよね。。。
というわけで結論。Windows では確かにこのような形で connect() にタイムアウト処理を加えることはできます。でも UNIX の慣習とは違い connect() が成功しない限り select() は 0 を返すばかりなので,結局「成功」「タイムアウト」のどちらかしか無くなります。
てか,こんなに安易に結論を出しちゃっていいのか自分!?
忘れるところだった:非同期で connect() を開始した時,UNIX Socket では connect() が -1 を返し errno が EINPROGRESS を返しますが,Windows では errno を見るのではなく GetLastError() が WSAEWOULDBLOCK であることを確認するべきのようです。どうも WSAEINPROGRESS ではない模様。なんだかなー。
ついでに余談:FormatMessage() API で GetLastError() のエラーコードを文字列に変換するコードは 2002-06-25 で示した通り。しかし WindowsMe では,この関数に WSAEWOULDBLOCK を入力してもエラーメッセージが取得できていないっぽいんですよね。確かに文字列バッファは割り当てられているんだけど,内部のデータは印字可能文字とはどうも違うっぽくて,printf("%s") で印字しようものならば「ピー」とかビープが鳴っちゃいます。なんでだろう???
ここで追記:どうも FormatMessage() ( の中の LocalAlloc() かな? ) が壊れていた模様でした。本来はメッセージバッファへのポインタに NULL が返されるべきだったんですね。
疲労度:9852
Sleep() API があるから大丈夫っすけどね。曇り空だとさすがに涼しいというか,むしろ寒いくらいですね。夜間の気温はおそらく 20 度を切っているはず。しかし私の部屋は相変わらず外気温よりも遥かに高く,0 時現在で 26 度。今が一番すごしやすい時期です。
さて最近はなぜか何の脈絡もなくフォントに関係する API をいじっていますが,さっそくわけのわからない挙動に出くわしました。今日のコードはこんなの。
#include <windows.h>
#include <stdio.h>
int CALLBACK enumFontsProc(
ENUMLOGFONT *pLF,
NEWTEXTMETRIC *pNM,
DWORD n,
LPARAM lp )
{
printf("%s(%s) %s %2d fonttype = %s %s %s\n",
pLF->elfFullName,
pLF->elfLogFont.lfFaceName,
pLF->elfStyle,
pLF->elfLogFont.lfHeight,
n & DEVICE_FONTTYPE ? "DEVICE" : "\b",
n & RASTER_FONTTYPE ? "RASTER" : "\b",
n & TRUETYPE_FONTTYPE ? "TrueType" : "" );
return 1;
}
int main(int argc, char *argv[]) {
HDC dc = ::GetDC(HWND_DESKTOP);
::EnumFontFamilies( dc,
argc>1 ? argv[1] : 0,
(FONTENUMPROC)enumFontsProc,
0 );
::ReleaseDC(HWND_DESKTOP, dc);
return 0;
}
昨日はフォントの列挙に EnumFonts() API を使いましたが,今日はより詳しいフォントの情報を得るために EnumFontFamilies() API を使ってみました。このコードを実行する時にはぜひ引数にフォント名を与えてやりましょう。フォント名の多くには空白文字が含まれており,そのままタイプしても引数の区切りと見なされ,argv[2] や argv[3] の要素になってしまうだけです。ちゃんとクオーテーションマークで囲んでやりましょう。
E:\TEST>program "Times New Roman"
さて,その引数に「MS 明朝」を指定してみます。
MS 明朝(MS 明朝) 標準 33 fonttype = TrueType
そんなに驚くべき結果ではありません。まぁこんなもんですよね。次,引数に「MS ゴシック」を指定してみると・・・
MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType MS ゴシック(MS ゴシック) 標準 33 fonttype = TrueType
なんかズラッと出たしっ!?・・・一体この挙動は何なのか,ちょっと課題にしておこうと思います。むむ・・・
疲労度:48
ネタ元は /.J より。アポロが月に行った事を信じていないテレビ番組制作者さんが,史上 2 番目に月に降り立った Aldrin さんを「お前月に行ってないんだろう? 白状しろやコラ」と煽って,Aldrin さんから殴られたとか。
うーん,なんだろう,もう,こう,なんていうか・・んー・・。
使用可能なフォントの列挙には EnumFonts() API を使用するのが簡単ですが,しかしナメてるとアプリケーションが落ちます。少しびっくりしました。
// !注意!このコードを実行するとアクセス違反が発生するかも!
// コンパイルおよび実行は各自の責任で!
#include <windows.h>
#include <stdio.h>
int enumFontsProc(
const LOGFONT *pLF,
const TEXTMETRIC *pNM,
DWORD n,
LPARAM lp )
{
puts( pLF->lfFaceName );
return 1;
}
int main() {
HDC dc = ::GetDC(HWND_DESKTOP);
::EnumFonts( dc,
0,
(FONTENUMPROC)enumFontsProc,
0 );
::ReleaseDC(HWND_DESKTOP, dc);
return 0;
}
このコードでアプリケーションが落ちる原因はコールバック関数 enumFontsProc() にあります。VC++5.0 のデフォルトの設定は関数宣言が __cdecl。しかし EnumFonts() API に渡すコールバック関数は __stdcall でなければなりません。
というわけで,正解は次のとおり。このようなコールバック関数の場合,可読性のために CALLBACK マクロを使うというのは良い習慣だと思います。
int CALLBACK enumFontsProc(
const LOGFONT *pLF,
const TEXTMETRIC *pNM,
DWORD n,
LPARAM lp )
{
puts( pLF->lfFaceName );
return 1;
}
疲労度:12
ようやく lfHeight の正/負の違いによるフォントサイズの差を見ることができました。簡単な 比較ページ ( 20020914.htm ) を用意したのでどうぞ。
結局 SetMapMode() API でマッピングモードを変更するのが重要でした。今回の調査では MM_ISOTROPIC と MM_ANSITROPIC は扱っていませんが,これらが特に重要ではないからです。あと,面倒くさかったしね。
疲労度:61
昨日の続きって事でいいのかな? LOGFONT::lfHeight メンバに正の値と負の値を入れた場合では若干表示が違ってくるという情報を手に入れたので,試しに本当に表示させてみました。それぞれストックオブジェクトのフォントを取得した後で,上は lfHeight = 60,下は lfHeight = -60 を行っています。
繰り返しますが,上は lfHeight = 60,下は lfHeight = -60 です。まったく違いが分かりません。実験の仕方が違うのかなあ・・・。
このあたり,まだまだ調査が必要な模様です。
疲労度:17
実験はなんとなく期待通りにはならなかったけど,しかし転んでもただでは起きない k|m です。まずこのテのフォントは高さを指定しても大体無意味だということ。高さを自由に変えられるのは DEFAULT_GUI_FONT で用いられている MS UI Gothic ですね。ANSI_VAR_FONT で用いられている MS Sans Serif も多少は大きさを変えられるようですが,さすがに lfHeight で指定した "60" とまでは行かないようです。
問題は DEVICE_DEFAULT_FONT ですが,見たところこれは MS ゴシック が選択されたようです。WindowsMe では DEVICE_DEFAULT_FONT からフォントオブジェクトが取得できませんが,それでもなんとか無理やり CreateFontIndirect() API でフォントを生成しようとしたもんだから,システムが本当にデフォルトなフォントを自動で選択したわけですね。しかし昨日の「追記」の方にも記述した通り,Windows2000 では DEVICE_DEFAULT_FONT から System というフォントが取得できます。さらにこれは上の画像でも分かるように 18 ポイント固定。このあたりをヘタに扱っていると,Win9x/Me と 2000 では思わぬ画面の崩れに遭遇する事もあり得るので注意が必要です。
ストックオブジェクトから各構造体 ( LOGFONT など ) への変換の仕方は 2002-07-13 で扱った通り。どうせネタを振ったんで最後まで責任をとって,ここでストックされている各フォントの中身をリストアップしちゃいます。なお以下のリストは WindowsMe にて調査されたもの。他の OS では少し違いがあるかも知れません。
OEM_FIXED_FONTlfFaceName .. "Terminal"lfHeight .. 18ANSI_FIXED_FONTlfFaceName .. "Courier"lfHeight .. 12ANSI_VAR_FONTlfFaceName .. "MS Sans Serif"lfHeight .. 12SYSTEM_FONTlfFaceName .. "System"lfHeight .. 18DEVICE_DEFAULT_FONTlfFaceName .. ""lfHeight .. 0SYSTEM_FIXED_FONTlfFaceName .. "FixedSys"lfHeight .. 18DEFAULT_GUI_FONTlfFaceName .. "MS UI Gothic"lfHeight .. -12ここで気になる部分がいくつかあります。まず DEVICE_DEFAULT_FONT に注目。どうやら LOGFONT が取得できなかったようですが,このオブジェクトが WinNT/2000 専用であるのに対して私のマシンの環境が WindowsMe だからですね。ちなみに LOGFONT の取得には失敗してもきちんと lfFaceName[0] にヌルが入る事を特筆しておきます。
そして DEFAULT_GUI_FONT はユーザーが画面のプロパティで変更されるフォントを表しますが,なんと lfHeight がマイナスの値をとっています。実はこのメンバ,正,0,負によって描画される文字の高さが多少変化するようなのです。特に欧米文字フォントではこれに気をつけるか気をつけないかによって大きく差が出るとか。これが意味するところについて,もうちょっと調べてみる必要がありそうです。
疲労度:8
Windows2000 で DEVICE_DEFAULT_FONT に使われているフォントを調べてみると,次のような結果が出ました。
DEVICE_DEFAULT_FONTlfFaceName .. "System"lfHeight .. 18つまり SYSTEM_FONT と同じですね。