かとんぼさんからご指摘頂いた。(もう「また」とかつけない。だって「またまたまたまた・・・・」になっちゃうもん)
今回は、ループ内で
enum_windows_proc = lambda {|hwnd| puts hwnd; -1}
11.times do
EnumWindows(enum_windows_proc, 0)
end
などとすると、1.9では5回を超えると、1.8では10回を超えるとエラーになるというもの。まぁループの中でCallbackを使うことはないだろうと多寡をくくって手を抜いていたのがばれてしまったというのが真相。
swinapi.rb, swinapi.c 共に修正してコミットした。あ swinapi.c は置き場のを更新してある。
ということで毎度ありがとうございます。
またまたかとんぼさんから頂いた。
今回はタスクトレーのメッセージハンドラの不具合。vrtrayballoonをrequireする(つまりデフォルトの状態)と、self_trayrbuttondown以外のハンドラに反応しなくなり、またWM_MOUSEMOVEもself_trayrbuttondownが拾ってしまうというもの。
実はこの不具合は、現在のリリース版である080229で起きているもので、それをかとんぼさんの御指摘とパッチにより、おいらがHEADで修正していた。VR_M17Nはかなり前から手がけていて、そのときはHEADではなく、このリリース版に手を入れて実験していた。去年ある程度目鼻がついた時点で、HEADに対しての修正に切り替えたのだが、cvs でコンフリクトが起きると、かえって面倒くさいことになるので、この切り替えは全て手作業で行った。まぁこのブランチはコミットするまでに何度か書き直しており、そのうちの書き直し1回の中で、ついでに HEAD に切り替えただけのことで、作業自体は想定内だったのだが、その時に見落としてしまった。
ローカルでは subversion で管理していたから、svn で一旦ブランチを切り、Trunc を cvs の HEAD に切り替えてから merge すれば多少ましだったのかもしれないが、svn も git ほどにはちゃんと merge できないという先入観があったため、この程度なら手作業のほうが早かろうというわけでやっつけてしまった。
というわけで頂いたパッチを当ててコミットした。
これから他にHEADからの漏れがないか確認してみる。
やはり漏れがあった。VRStaticでマウスクリックを拾うためにはSS_NOTIFYスタイルを設定しておかなければならないのだが、そのための定数とリファレンスをにゃすさんが追加・修正しておられた。これを落としていた。で、コミットした。
これ以外に080229以降の修正はもう1点vrrichedit.rbであったが、こちらは PARAFORMAT構造体を書き換えた時点で修正してあった。これ以外にはHEADとの食い違いは多分ないはず。
またまたかとんぼさんからパッチを頂いた。毎度ありがとうございます。
今回は、SWin::API.defun で VOID* のようなポインタ型の戻り値を指定すると弾かれるというもの。で、今コミットした。パッチは以下。
@@ -322,7 +322,7 @@ - when /^([\w\s]+)\(([\w\*\s\,\[\]]*)\)$/ + when /^([\w\*\s]+)\(([\w\*\s\,\[\]]*)\)$/
あと、他にもいろいろ頂いた。
まず、SWin::API.defunには面白い副作用があって、
SWin::API.defun 'HMODULE GetModuleHandle( LPCTSTR lpModuleName )'
なんて型と仮引数のペアを1つの引数として認識するというもの。何回か書いているが、defunは引数の数しかチェックしておらず、仮引数の型チェックをしない。型は実引数が渡されるときにRubyの型をCの型に変換している。だから引数はカンマで区切られた文字列なら何でも良いわけなので、こんなことができていた。これはCのヘッダーをパクる時に便利なので、ちゃんと検証して、オーソライズしよう。あと、ついでにCのコメント読み飛ばしができればさらによいな。
あと、CFuncのベンチマークをやってくださった。いずれやらなくてはいけないと思っていたので、大変ありがたい。で、それによるとCによるswinapi.cを有効にした場合は大体2倍程度速度が向上するとのこと。参考にしてください。いずれおいらもベンチマークを取るつもり。
さらにおいらの持っていないVC6でビルド、検証もやってくださっている。本当にありがたいことだ。
昨日だったか一昨日だったかOfficeのアップデートがあったのだが、今日になったら、他のマシンで使ってたWindows XP上のExcel2003のListViewが動かなくなるわXP上のExcel2007のUserForm上のIEは動かなくなるわ、Windows7 X64上のExcel2007のListViewは動かなくなるわ、もう大騒ぎ。で、Excel2003はMicrosoft Updateで解決したのだが、X64のExcel2007は「すでに最新です」でアップデートできない。
で、探したらhttp://support.microsoft.com/kb/2266789/jaなんてのがあった。つまりmscomctl32.ocxのバージョンミスマッチらしい。ここにはOffice2007→Office2010にアップグレードに限ると書いてあったが、どうやらそれがOffice全体に拡大してしまったようだ。解決方法はそこにあるとおりに管理者権限で
regsvr32 C:\Windows\System32\MSCOMCTL.OCX
としても失敗する。そりゃそうだ。
regsvr32 C:\Windows\SystemWOW64\MSCOMCTL.OCX
でなけりゃいけない。MicrosftUpdateで解決しない場合は試す価値あり。上のはWin32で使えるはず。ま、こういうひどいバグはすぐに修正版が出るんだろうけど。いい加減にしてほしい。
一昨日アナウンスがあった。
最低レベルが1GB Mem/100GB HDD になった。海外のに比べると、まだ割高なのだが、CPU/回線速度が圧倒的に速いようなので、十分ペイできるだろう。512MB/20GBで980円/月のときは、正直使い物になるか不安だったが、このスペックで980円/月なら画像を溜め込んだりせず、普通に使う分には全く問題ない。乗り換えキャンペーン中に手続きしておこう。
またまたかとんぼさんからパッチを頂いた。毎度ありがとうございます。 今度はRuby 1.8でSWin::API.encode_defaultに"A\0\0\0"なんて文字列を食わせた場合、これをUNICODEと誤認して、ゴミが出るというもの。頂いたパッチをさらしておく。
diff -u -r1.1.2.3 swinapi.rb
--- swinapi.rb 11 Mar 2012 14:01:42 -0000 1.1.2.3
+++ swinapi.rb 28 Mar 2012 00:24:36 -0000
@@ -507,7 +507,7 @@
buff = NULL * 256
r = WideCharToMultiByte(0,0,str, str.bytesize/2,buff,buff.size,nil,nil)
end
- r >0 ? buff[0, r] : str.gsub(/\0*$/,'')
+ (r >0 ? buff[0, r] : str).gsub(/\0*$/,'')
end
def encode_output(str) encode_default(str); end
本気でテストしてくださっているようで、本当にありがたいことだ。
こちらは、せっかくCでSendMessage/PostMessageを書いたのに、それを使わないようになっていたのを修正。
ということで置き場の swinapi.c を修正。これは、sysmod.rb で定義されている、GMEM::AllocStr が現在の実装だと1.9のVC10版では何をやってもSEGVってしまうため。
どこでSEGVるかというと、流れはGlobalAlloc → GlobalLock → memcpyになるわけだが、このmemcpyでSegmentationFaultになる。
GlobalLockが返すポインタには値がちゃんと入っているのだが、この値が正しくmemcpyに渡されないようだ。MinGWではこれは起こらないから、当然GVLが悪さをしているわけだが、この3つの関数をGVLから外しても駄目だし、さらにMutexを掛けても駄目。
まぁGVLの管理外の関数をRubyのインタプリタ(VM)から呼び出しても結局はそうなってしまうのかもしれない。これ以上試行錯誤するよりはCレベルで実装したほうが楽だし、以前からグローバルメモリの操作はSWin側で実装したほうが良いのではと思っていたので、良い機会と思いswinapi.cに実装してしまった。SWin::API.GlobalAllocStrとGlobalGetStrというのがそれ。これは生のAPIではないので、SWin::APIよりもSWin::Applicationで実装したほうが良いかもしれないが、当面Application側に手を入れるつもりはないので、このままとしておく。これによってsysymod.rb の書き換えも行った。
以下に続く。
てなわけで、sysmod.rbも改修した。ついでにSMSG::SendMessage / PostMessageもCレベルで実装した。これは自スレッドのウインドウにメッセージを送った場合、GVLに引っかかる可能性があるためと速度を要求される可能性があるためだ。call時にGVLを外す機構もswinapi.c には実装したため、速度のことを考えなければ別に以下の機構を使えばよいのだが、まぁついでのようなもの。
というわけで、さらに以下に続く。
さらに、てなわけでこちらも更新。こちらでは
SWin::API.defun_ubf
という特異メソッドを追加した。ubf とは UnBlocking Function のことだそうだ。こちらでAPI関数を定義すると関数呼び出し時にGVL(Global VM Lock Win32でスレッドを使うため、強制的に常時単一スレッドで動かす機構だそうだ。)を外すようになる。ま、これはswinのcall_thread_blocking をぱくっただけだが。この機構を使えばSendMessageは単に
SWin::API.defun_ubf 'SendMessage(HWND, UINT, WPARAM, LPARAM)'
と書けるのだが、まぁついでのようなもの。GVLを外さないとデッドロックする場合に使ってください。
ruby1.9 で TCHAR[xx]形式の文字列を生成するとSEGVるという致命的なバグがあったので、置き場の swinapi.c を修正。
ポインタにSWIN_API_STR()でエンコーディング変換をした文字列を食わせ忘れていたというお粗末(汗)。
すいませんが、今日までにダウンロードした方はやり直してください。
かとんぼ(北島)さんからまたパッチを頂いた。毎度ありがとうございます。
で、このパッチと共に、次への準備として、SWin::API.defstruct周りの非常にダサかったコードを整理したものをコミットした。module_evalに食わせる文字列を最小限にすると同時に、コンストラクタとメモリアクセスメソッドをCレベルで実装するための対応を行った。だから構造体クラスの生成は速くなっている。またCFunc,CallbackのC実装への対応もしてある。これはいつもの置き場に置いてあるのでvr.zipをダウンロードしてsite_rubyに展開してください。詳細はswinapi.rbを見てくださいな。
続いてこちらは上に書いたCレベルの実装。置き場から swinapi.c をダウンロードして、swinディレクトリに置く。でディレクトリにあるswin.cのInitswin(){}の最後の方に一行だけ以下を追加する。
Init_swinapi();
どの辺に書いたらよいかはコードを見ればすぐわかる。あとはextconf.rb を走らせて(n)makeすれば上記クラスのCレベル実装が入ったswin.soが出来上がる。これをsite_rubyのso置き場においてやればOK。速度もさることながらDL/Win32APIの仕様変更の不安から開放されるというのが、精神衛生上大変よろしいとおいらは思う。
このswin.soは少し(数十kb)大きくなる程度で、VR_M17Nブランチ以外のvrでは一切影響がないはずなので一応安心してくださって結構だ。コンパイルは gcc (TDM-1 mingw32) 4.4.0 で Ruby1.8.7p334 と 1.9.3p5、VC10pro では 1.9.3p5 で確認しているがVS2010EE/2008EEでも問題なくコンパイルできるはずだ。残念ながらVC6は持ってないので未確認だが、MinGWでビルドしたswin.soで動くことは確認してある。こちらは、nyasuさんのお許しが出れば、ブランチを切らずにいずれ HEAD に cvs add するつもり。
では、皆様よろしく願いします。
ということで、(3)と(4)を検証した。
(3) subclstest.rb
Edit1 に "あ" を入力すると落ちる。
これは、Windowsの仕様のせい。_UNICODEが立っていると、WM_CHARは2バイト分のコードを返す。従ってASCII互換文字以外は256以上の値が返ってくるため。つまり、Integer#chrは使用できない。これも1.8,1.9どちらでも動くようにサンプルを修正しよう。
(4) mediatest.rb
OPEN ボタンから、Open ダイアログで MP3 ファイルを指定すると落ちる。
こちらは完全にM17N対応不足。一世代前のコードのままで、現在のSWin::APIの仕様に合わせていなかった。vrmmedia.rbを修正して、ブランチにコミットしておきました。
今日はここまで。