つまり、このコールバック関数は、どのインスタンスが登録したものなのかを、自分で知ることができません。それどころか、どのソケットなのかすらもわかりません。
…これで昨日は悩んだわけですが、今日、HTTPサーバーからファイルを取り寄せるを見て、やっと解法がわかりました。LunaのOVERLAPEDDATA構造体の先頭にWSAOVERLAPPED構造体を配置し、その後ろに自分自身へのポインタを配置します。
struct OVERLAPEDDATA { WSAOVERLAPPED Overlap; LunaClientSocket * Client; // …略 };
WSASend/WSARecvをコールするときは、OVERLAPEDDATA構造体へのポインタを、WSAOVERLAPPEDへのポインタにキャストして渡せばいいだけです。コールバック関数は、受け取ったWSAOVERLAPPEDへのポインタを、OVERLAPEDDATA構造体へのポインタにキャストし直せば、OVERLAPEDDATA構造体経由でインスタンスへのポインタを取得することができます。もちろん、渡したポインタと受け取ったポインタが同じ場所を指している、というのが大前提ですけどね。
ところで、まだ一度も動作確認してないんですが…
Winsock2そのものと、LunaClient(or Server)Socketを管理・制御するための専用クラスを作成しました。管理下にあるソケット全てを一斉にクローズしたり、Winsock2の開始とシャットダウンを管理したり、まあそんな感じのことをします。吉里吉里プラグインとして使用中のソケットを監視制御するのに必要となるでしょう。特に、プラグインのアンリンク時にはしっかり解放してやらないと。
あれ?中華キャノンがないよ。ああそうか。剣を装備して近接格闘戦用になったから要らないのか(違)
ソースコード自動生成スクリプトmakekrnc.plを改良して、引数と戻り値についても記述できるようにしました。今までアレなマクロで書いていた部分が、さらにアレな記述になりました。
TVP_PLUGIN_FUNCCALL_DECL(tHogeFunction) { TP_REQ_NUM_PARAMS(2) TP_GET_REQ_PARAM_INT(x) TP_CHK_PARAM_MUST_OBJ TP_GET_REQ_PARAM_CLO(cond) // 中略 TP_SET_RETURN_VALUE_INT(rv) return TJS_S_OK; }
@function hoge @params 2 @par int x @must obj @par vclo cond // 中略 @return int rv return TJS_S_OK; @;
もはやスクリプトなしではコンパイルすらできませんが、もともとスクリプトに頼りきりだったので、今更依存部分が増えたところで大して変わりません。
libiconvに関する良い資料が見つからず、手こずりました。以下、Borland C++ Compilerで使うときのメモ。
プログラムする上での注意点。
cd == (iconv_t)(-1)
で比較して必ずエラーチェックすること。なぜiconvなんかを弄っているかというと、文字の符号化変換モジュールを作成するためです。このモジュールは、吉里吉里が内部で持っているワイド文字列(16ビット体系かな?)と、符号化されたオクテット列との相互変換を行います。
前々から欲しいと思っていた *1 、というのもありますが、ソケットを使う上でいずれ必要になる、というのが大きいです。例えば、文字列の送受信等で、通信相手が、自分とは異なる特定の符号化方法しかサポートしていない場合、符号化方法を変換してあげる必要がありますから。
…いや、そもそもソケットプラグインではオクテット列の送受信しか対応しない予定 *2 なので、文字列送受信には必須になるかもしれません。
libiconvって、LGPLなんですよね。吉里吉里のプラグインは、できれば吉里吉里独自のライセンスか、BSDライセンスか、あるいは「好きにしてくれ状態」で公開したいと考えているので、気をつけて扱わないとGPL汚染されてしまいます。まあ、動的リンクだから問題ないか。
文字の符号化方法を変換する機構を作成しました。perlみたいに、Encoder.encode(encname, text)
、Encoder.decode(encname, octet)
で変換できます。EUC-JPでもMacArabicでも何でも来やがれ、て感じですかね。
バイナリファイルを読み書きするためのクラスを作成しました。普通にdata = stream.read(SIZE)
とかwritten = stream.write(octet, SIZE)
みたいに扱えます。
こういうのを作っておけば、ソケットのテストが多少は楽になるでしょう。
serial experiments lain TV-BOXが届きました。暇を見つけて鑑賞しましょう。
なんか、バイナリファイルストリームにかかりっきりで、ソケットの作業が全然進んでません。連休中にクライアントくらいは、と思っていたのですが。うーむ。
送信完了時コールバック関数自体は実行されているのですが、内部でキックしているはずのTJS関数が期待通りに動いてくれていない様子。FuncCall()自体は例外も出さず、戻り値も0なのですが、実行結果が反映されていません。うーむ。
3x3メジアンフィルタ。符号なし8ビット、要素数9の配列から、メジアンを取得するロジックが浮かんだので、実装してみました。今まではクイックソートで並べてから真ん中の要素を抽出していましたが、これを基数ソート+バブルソート+クイックソートの変態複合型(?)に変えました。真面目にソートしないのがポイントです。
他の方法と比較したところ、当社(独自実装のクイックソート)比で約二倍、C標準のqsort関数の約四倍の速度になりました。ただ、これは値が平均的にばらついていた場合の話で、配列中の要素の値が極端に偏っている(エントロピーが小さい)場合は却って遅くなります。メジアンフィルタに適用した場合、ベタ塗りのアニメ調の画像では重くなりやすい、ということです。
あまりにアレなカラーイコライゼーションの実装を改善しました。
あと、イメージバッファ比較関数を書きました。これを使えば、リグレッションテストが多少は楽になるかな。