著作一覧 |
Ruby 1.9.1で組み込みRubyをプログラミングするには、1.8のときより必須事項が増えているので、それについて示してみます。ただしWin32用です。
以下が標準的なコード(C++用にしてみたり)となると思います。(20090206参照)
#define WIN32_LEAN_AND_MEAN #include <windows.h> #include "ruby.h" extern "C" { #include "ruby/encoding.h" } static char* test_src[] = { "begin\n", " require 'test/unit'\n", "rescue => e\n", " puts \"#{e}\"\n", "end\n", "puts RUBY_VERSION\n", "gets()\n", "\n"}; int main(int argc, char* argv[]) { #if defined(USE_ARGS) ruby_sysinit(argc, argv); #else static int dummyargc(0); static char** vec; ruby_sysinit(&dummyargc, &vec); #endif ruby_init(); // GC用にスタックポインタを設定、vmの起動 #if defined(USE_ARGS) ruby_options(argc, argv); #else // ruby_options(process_options)の処理を肩代わり ruby_script("Embeded Ruby"); // BT採取で死ぬので必須 VALUE enc = rb_enc_from_encoding(rb_locale_encoding()); rb_enc_set_default_external(enc); // コメント欄参照。 rb_enc_set_default_internal(enc); // ruby_init_loadpath(); // 常識的に必須(ruby/ver/arch,site_ruby,site_ruby/ver,site_ruby/ver/archなどが設定される) #endif rb_require("win32ole"); // 拡張ライブラリのロード char szTemp[_MAX_PATH]; GetTempPathA(_MAX_PATH, szTemp); char szTempFile[_MAX_PATH]; GetTempFileNameA(szTemp, "rb1", 0, szTempFile); HANDLE h = CreateFile(szTempFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); for (int i = 0; i < sizeof(test_src)/sizeof(char*); i++) { DWORD dw; WriteFile(h, test_src[i], strlen(test_src[i]), &dw, NULL); } CloseHandle(h); int state = 0; for (i = 0; szTempFile[i]; i++) { if (szTempFile[i] == '\\') szTempFile[i] = '/'; } rb_load_protect(rb_str_new2(szTempFile), 0, &state); if (state) { printf("script error %d\n", state); } ruby_finalize(); return 0; }
問題点:win32では、fcloseがrb_w32_fcloseに置き換えられ、しかもそこでクラッシュする(fflushでINVALID FILE*になる)。……でも、win32/win32.cを読む限り、それはおかしいな。後で調べてみることにする。
ジェズイットを見習え |
default_external の設定が必要なのはわかりますが、rb_enc_set_default_internal(enc); はなくても動きませんか。<br>default_internal の機能が必要というのならわかりますが、まぁコメントには書いた方がいいでしょうね。
どうもありがとうございます。<br>>rb_enc_set_default_internal(enc); はなくても動きませんか。<br>これは試してなかったので試してみます(良く分からないのでスキップした処理で関係しそうなやつを拾う、で動かしたからですね)。うまく動くようなら上のコメントアウトします。
だめでした。ということは、Win32OLEの問題かな?<br>Win32OLEが、default_internalがnilの場合は、コードページをdefault_externalに設定しているからですね。というか、設定しない=nilで良いの?
設定しない=nilですね。<br>nilを明示的にセットしないとダメなのかな、rb_enc_set_default_internal(Qnil);とか。<br>「ダメ」というのは先述のCP932とUS-ASCIIでなんとか?ってやつですかね。
だめの意味はその通りです。あと、上ではnilと書いてしまいましたが、NULLですね。
> Win32OLEが、default_internalがnilの場合は、コードページをdefault_externalに設定しているからですね<br>と、すると、Win32OLE 内の cp でなく、どこかで default_internal 設定の作用が働いてるのでしょう。<br><br>改めて確認しますが、CP932 と US-ASCII というメッセージは正確にはどんなメッセージでしたか。<br>少なくとも「CP932」は「Windows-31J」のはずです。<br><br>あと、rb_enc_check(fname, result);でエラーが発生しているとすると、<br>Windows-31J と US-ASCII だと compatible のはずです。<br>エラーが発生しているならば、fname も result も中に、<br>非 ASCII な文字列が紛れ込んでいると思われるんですが、<br>「'mini/test'の中でFile.expand_path __FILE__している箇所」だとすると、<br>イマイチここでそうなる理由がわかりません。
1個思い出したことがあるので、夜になったら試すけど、エンコーディングが見つからない時の例外を避けるために(ruby_scriptに気付く前)空のCp932をencの下に置いて、そのままだったような気がする。それで、非互換なのかも。
上の件は関係なかったようです(削除した)。エラーメッセージは、<br>incompatible character encodings: CP932 and US-ASCII<br>です。default_internalを設定すればエラーにならない(default_externalへの設定は影響しない)ことも同じでした。
>少なくとも「CP932」は「Windows-31J」のはずです。 <br>Cp932というのは、win32ole.cのole_cp2encodingで作ったエンコーディングみたいですね。
ソース読まずに考えると、default_internalにrb_enc_from_encoding(rb_locale_encoding())を設定することで、Cp932 エンコーディング(Windows31-Jのエイリアス?)が作成されて、Win32OLEがそれを利用できるようになるけれど、それをしないとCp932が存在しないので、Win32OLEがダミーのCp932を作り、それが利用され、しかもUS-ASCIIと非互換ということではないでしょうか?
あー、直接的な原因はそれですね > Win32OLEがダミーのCp932を作り<br><br>ゆえに、今の謎は、<br>* なぜ CP932 で Windows-31J をとってこれないのか<br>* なぜ、rb_set_default_internal すると通るのか<br>ですか。<br><br><br>仮説としては、<br>まず、そもそも現在は組み込みエンコーディング (US-ASCII, ASCII-8BIT, UTF-8) しかとれておらず、Windows-31J は実はとれていない。<br>で、default_internal を設定すると通るのは、そもそも locale_encoding からして CP932 を取れていなくて ASCII-8BIT が入っている。defalt_internal にも locale_encoding = ASCII-8BIT が入り、Win32OLE は default_internal をコードページの代わりに使うのでダミーの CP932 を定義せず、動いているように見える。<br><br>検証するには、<br>* Encoding.list がどうなっているか見る→組み込みしかないのではないか<br>* Encoding.find("locale") がどうなっているかみる→ASCII-8BIT になっているのではないか<br>* 一見成功するとき rb_enc_check(fname, result);のfnameとresultがどうなっているか見る→ASCII-8BITとUS-ASCIIではないか<br><br>上のソースコードを見てもrb_enc_find_index("encdb");してるruby_optionsやprocess_optionsが通ってない可能性がありますし。
むむ、rb_enc_find_index("encdb"); というのが必要なのか。というのはさておき、試してみます。
ruby_process_options()呼び出しは必須という形で設計されてるはずなので、無理に分解しないで素直に呼んだ方がいいと思います。
1.9からは必須ということでもいいけど、ついでだから分解は、しときたいな。組み込んでいる側のコマンドラインをRubyに見せたくないって時に、安心感が得られるし。
rb_enc_find_index('encdb')実行前は、US-ASCII,UTF-8だけで動いていて、default_external、default_internalのいずれの場合でもWin32OLEのダミーCP932が作られていました。<br>いずれの場合も$0はASCII-8BITになります。