From: nobu.nakada@... Date: 2002-01-22T01:48:01+09:00 Subject: [ruby-dev:15748] Re: Win32API enhancement なかだです。 At Mon, 21 Jan 2002 15:52:37 +0900, U.Nakamura wrote: > ・win32にはコールバック関数がたくさんあるが、ウィンドウプロシ > ージャをこうやって対応しちゃうと、他のコールバック関数に対 > 応したくなったときに収拾が取れなくなる。 > むしろコールバック関数を扱う統一的な機構を考えた方がいいの > では。 こんなのとか(謎)。動くかどうかどころか、コンパイルできるかどう かも保証の限りじゃありませんが。 # 引数の順番が逆だったかも。 # win32/callback/extconf.rb if /i\d86-(?:cygwin|mingw|mswin)/ =~ RUBY_PLATFORM create_makefile("callback") end /* win32/callback/callback.c */ #if !defined _MSC_VER && !defined NT #define WIN32_LEAN_AND_MEAN #include #endif #include #include "ruby.h" #ifndef EXPLICIT_RETADDR #define EXPLICIT_RETADDR 1 #endif static ID id_yield; struct callback_arg { int nargs; VALUE obj; ID id; int (*defproc)(); }; static VALUE invoke_callback(VALUE *arg) { const struct callback_arg *carg = (struct callback_arg *)*arg++; return rb_funcall2(carg->obj, carg->id, carg->nargs, arg); } static int CALLBACK win32_callback( #if EXPLICIT_RETADDR int (**retaddr)(), #endif const struct callback_arg *carg, va_list vargs) { int status, nargs = carg->nargs; VALUE *args = ALLOCA_N(VALUE, nargs+1), *p = args, ret; *p++ = (VALUE)carg; for (nargs = carg->nargs; nargs > 0; --nargs) { int arg = va_arg(vargs, int); *p++ = INT2NUM(arg); } ret = rb_protect((VALUE (*)_((VALUE)))invoke_callback, (VALUE)args, &status); if (status && carg->defproc) { #if EXPLICIT_RETADDR *retaddr = carg->defproc; #else ((int (**)())&carg)[-1] = carg->defproc; #endif return 0; } if (NIL_P(ret)) return 0; return INT2FIX(ret); } #ifdef _M_IX86 # if EXPLICIT_RETADDR # define THUNK_SIZE (sizeof(struct callback_arg) + 6 + 13) # else # define THUNK_SIZE (sizeof(struct callback_arg) + 6 + 8) # endif #else # error "unsupported architecture" #endif static VALUE win32_callback_initialize(int argc, VALUE *argv, VALUE self) { VALUE obj, nargs, defproc, code; ID id; unsigned long n; char *p; if (rb_block_given_p()) { obj = rb_f_lambda(); id = rb_intern("yield"); rb_scan_args(argc, argv, "11", &nargs, &defproc); } else { VALUE vid; rb_scan_args(argc, argv, "31", &obj, &vid, &nargs, &defproc); id = rb_to_id(vid); } if ((n = NUM2ULONG(nargs)) > 255) { rb_raise(rb_eArgError, "too many arguments %lu", n); } rb_str_resize(self, THUNK_SIZE); p = RSTRING(self)->ptr; #ifdef _M_IX86 *p++ = 0x54; /* push %esp */ *p++ = 0xe8; /* call 1f */ *(LONG *)p = sizeof(struct callback_arg); p += sizeof(LONG); { struct callback_arg *carg = (struct callback_arg *)p; carg->nargs = nargs; carg->obj = obj; carg->id = id; carg->defproc = (int (*)())(NIL_P(defproc) ? 0 : defproc); p = (char *)++carg; } /* 1: */ # if EXPLICIT_RETADDR *p++ = 0x8d; *p++ = 0x44; *p++ = 0x24;*p++ = 0xf8; /* leal -8(%esp), %eax */ *p++ = 0x50; /* push %eax */ # endif *p++ = 0xe8; /* call call_callback */ *(LONG *)p = (LONG)win32_callback - (LONG)p - sizeof(LONG); p += sizeof(LONG); *p++ = 0xc2; /* ret nargs*4 */ *(WORD *)p = nargs * 4; p += sizeof(WORD); #endif rb_str_associate(self, rb_ary_new4(1, &obj)); rb_obj_freeze(self); return self; } static VALUE win32_callback_address(VALUE self) { return INT2NUM((long)RSTRING(self)->ptr); } void Init_callback(void) { VALUE mWin32 = rb_define_module("Win32"); VALUE cCallback = rb_define_class_under(mWin32, "Callback", rb_cString); rb_define_method(cCallback, "initialize", win32_callback_initialize, -1); rb_define_method(cCallback, "address", win32_callback_address, 0); id_yield = rb_intern("yield"); } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦