From: wanabe Date: 2008-07-18T18:13:26+09:00 Subject: [ruby-dev:35576] Re: [BUG] cfp consistency error in Win32OLE ワナベです。 Thread を使わずに例外を捕捉する方法を1つ思いつきました。 内部で rb_rescue 等で例外を受け取って保存し、 安全な場所からもう一度通知しなおすのはどうでしょうか。 今回も実使用には耐えないコードですが、イメージが伝われば幸いです。 Index: win32ole.c =================================================================== --- win32ole.c (revision 18123) +++ win32ole.c (working copy) @@ -3178,6 +3178,16 @@ return argv; } +static void +check_err(VALUE self) { + VALUE err = rb_ivar_get(self, rb_intern("err")); + + if (!NIL_P(err)) { + rb_ivar_set(self, rb_intern("err"), Qnil); + rb_funcall(rb_mKernel, rb_intern("raise"), 1, err); + } +} + static VALUE ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) { @@ -3400,6 +3410,7 @@ StringValuePtr(cmd), StringValuePtr(v)); } + check_err(self); obj = ole_variant2val(&result); VariantClear(&result); return obj; @@ -7425,6 +7436,21 @@ } } +VALUE EVENTSINK_Invoke_procall(VALUE *pargs) +{ + return rb_apply(pargs[0], rb_intern("call"), pargs[1]); +} + +VALUE push_exc(VALUE obj, VALUE e) +{ + if (rb_obj_is_kind_of(obj, cWIN32OLE)) { + if (NIL_P(rb_ivar_get(obj, rb_intern("err")))) { + rb_ivar_set(obj, rb_intern("err"), e); + } + } + return Qnil; +} + STDMETHODIMP EVENTSINK_Invoke( PEVENTSINK pEventSink, DISPID dispid, @@ -7491,7 +7517,11 @@ } } else { - result = rb_apply(handler, rb_intern("call"), args); + VALUE pargs[2]; + pargs[0] = handler; + pargs[1] = args; + result = rb_rescue(EVENTSINK_Invoke_procall, (VALUE) pargs, + push_exc, rb_ivar_get(obj, rb_intern("ole"))); if(TYPE(result) == T_HASH) { hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams); result = hash2result(result); @@ -7938,6 +7968,7 @@ poleev->pConnectionPoint = pConnectionPoint; poleev->event_id = pIEV->m_event_id; + rb_ivar_set(self, rb_intern("ole"), ole); return self; } cfp consistency error の根本原因も探ってみたのですが断念しました。 2回目以降の EVENTSINK_Invoke の呼び出しで rb_raise のジャンプ先がおかしくなっているように見受けられましたが それ以上追いきれませんでした。 -- ワナベ