summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--ext/win32ole/win32ole.c116
-rw-r--r--test/win32ole/test_win32ole_event.rb130
3 files changed, 192 insertions, 61 deletions
diff --git a/ChangeLog b/ChangeLog
index 3b31c25ff0..c8c6b804fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Sat Jul 26 21:17:18 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (Init_win32ole): add
+ WIN32OLE_EVENT#handler=, WIN32OLE_EVENT#handler
+
+ * test/win32ole/test_win32ole_event.rb: ditto.
+
Sat Jul 26 07:44:14 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
* ext/win32ole/win32ole.c (add_event_call_back): remove unused
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c
index afe9843adf..22cec8e49d 100644
--- a/ext/win32ole/win32ole.c
+++ b/ext/win32ole/win32ole.c
@@ -118,7 +118,7 @@
#define WC2VSTR(x) ole_wc2vstr((x), TRUE)
-#define WIN32OLE_VERSION "1.2.9"
+#define WIN32OLE_VERSION "1.3.0"
typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
(REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
@@ -499,6 +499,7 @@ static VALUE foleparam_default(VALUE self);
static VALUE foleparam_inspect(VALUE self);
static long ole_search_event_at(VALUE ary, VALUE ev);
static VALUE ole_search_event(VALUE ary, VALUE ev, BOOL *is_default);
+static VALUE ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler);
static void ole_delete_event(VALUE ary, VALUE ev);
static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams);
static VALUE hash2result(VALUE hash);
@@ -520,6 +521,8 @@ static VALUE fev_on_event(int argc, VALUE *argv, VALUE self);
static VALUE fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self);
static VALUE fev_off_event(int argc, VALUE *argv, VALUE self);
static VALUE fev_unadvise(VALUE self);
+static VALUE fev_set_handler(VALUE self, VALUE val);
+static VALUE fev_get_handler(VALUE self);
static VALUE evs_push(VALUE ev);
static VALUE evs_delete(long i);
static VALUE evs_entry(long i);
@@ -7434,6 +7437,23 @@ ole_search_event(VALUE ary, VALUE ev, BOOL *is_default)
}
return def_event;
}
+static VALUE
+ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler)
+{
+ VALUE mid;
+
+ *is_default_handler = FALSE;
+ mid = rb_to_id(rb_sprintf("on%s", StringValuePtr(ev)));
+ if (rb_respond_to(handler, mid)) {
+ return mid;
+ }
+ mid = rb_intern("method_missing");
+ if (rb_respond_to(handler, mid)) {
+ *is_default_handler = TRUE;
+ return mid;
+ }
+ return Qnil;
+}
static void
ole_delete_event(VALUE ary, VALUE ev)
@@ -7502,8 +7522,9 @@ exec_callback(VALUE arg)
{
VALUE *parg = (VALUE *)arg;
VALUE handler = parg[0];
- VALUE args = parg[1];
- return rb_apply(handler, rb_intern("call"), args);
+ VALUE mid = parg[1];
+ VALUE args = parg[2];
+ return rb_apply(handler, mid, args);
}
static VALUE
@@ -7540,9 +7561,11 @@ STDMETHODIMP EVENTSINK_Invoke(
unsigned int i;
ITypeInfo *pTypeInfo;
VARIANT *pvar;
- VALUE ary, obj, event, handler, args, outargv, ev, result;
- VALUE arg[2];
- VALUE is_outarg;
+ VALUE ary, obj, event, args, outargv, ev, result;
+ VALUE handler = Qnil;
+ VALUE arg[3];
+ VALUE mid;
+ VALUE is_outarg = Qfalse;
BOOL is_default_handler = FALSE;
int state;
@@ -7564,9 +7587,21 @@ STDMETHODIMP EVENTSINK_Invoke(
}
ev = WC2VSTR(bstr);
event = ole_search_event(ary, ev, &is_default_handler);
- if (NIL_P(event)) {
- return NOERROR;
+ if (TYPE(event) == T_ARRAY) {
+ handler = rb_ary_entry(event, 0);
+ mid = rb_intern("call");
+ is_outarg = rb_ary_entry(event, 3);
+ } else {
+ handler = rb_ivar_get(obj, rb_intern("handler"));
+ if (handler == Qnil) {
+ return NOERROR;
+ }
+ mid = ole_search_handler_method(handler, ev, &is_default_handler);
+ }
+ if (handler == Qnil || mid == Qnil) {
+ return NOERROR;
}
+
args = rb_ary_new();
if (is_default_handler) {
rb_ary_push(args, ev);
@@ -7577,8 +7612,6 @@ STDMETHODIMP EVENTSINK_Invoke(
pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
rb_ary_push(args, ole_variant2val(pvar));
}
- handler = rb_ary_entry(event, 0);
- is_outarg = rb_ary_entry(event, 3);
outargv = Qnil;
if (is_outarg == Qtrue) {
outargv = rb_ary_new();
@@ -7593,7 +7626,8 @@ STDMETHODIMP EVENTSINK_Invoke(
* and exit ruby process by Win32OLE itself.
*/
arg[0] = handler;
- arg[1] = args;
+ arg[1] = mid;
+ arg[2] = args;
result = rb_protect(exec_callback, (VALUE)arg, &state);
if (state != 0) {
rescue_callback(Qnil);
@@ -8260,6 +8294,64 @@ evs_length()
return rb_funcall(ary_ole_event, rb_intern("length"), 0);
}
+/*
+ * call-seq:
+ * WIN32OLE_EVENT#handler=
+ *
+ * sets event handler object. If handler object has onXXX
+ * method according to XXX event, then onXXX method is called
+ * when XXX event occurs.
+ *
+ * If handler object has method_missing and there is no
+ * method according to the event, then method_missing
+ * called and 1-st argument is event name.
+ *
+ * If handler object has onXXX method and there is block
+ * defined by WIN32OLE_EVENT#on_event('XXX'){},
+ * then block is executed but handler object method is not called
+ * when XXX event occurs.
+ *
+ * class Handler
+ * def onStatusTextChange(text)
+ * puts "StatusTextChanged"
+ * end
+ * def onPropertyChange(prop)
+ * puts "PropertyChanged"
+ * end
+ * def method_missing(ev, *arg)
+ * puts "other event #{ev}"
+ * end
+ * end
+ *
+ * handler = Handler.new
+ * ie = WIN32OLE.new('InternetExplorer.Application')
+ * ev = WIN32OLE_EVENT.new(ie)
+ * ev.on_event("StatusTextChange") {|*args|
+ * puts "this block executed."
+ * puts "handler.onStatusTextChange method is not called."
+ * }
+ * ev.handler = handler
+ *
+ */
+static VALUE
+fev_set_handler(VALUE self, VALUE val)
+{
+ return rb_ivar_set(self, rb_intern("handler"), val);
+}
+
+/*
+ * call-seq:
+ * WIN32OLE_EVENT#handler
+ *
+ * returns handler object.
+ *
+ */
+static VALUE
+fev_get_handler(VALUE self)
+{
+ return rb_ivar_get(self, rb_intern("handler"));
+}
+
static void
olevariant_free(struct olevariantdata *pvar)
{
@@ -8896,6 +8988,8 @@ Init_win32ole()
rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1);
rb_define_method(cWIN32OLE_EVENT, "off_event", fev_off_event, -1);
rb_define_method(cWIN32OLE_EVENT, "unadvise", fev_unadvise, 0);
+ rb_define_method(cWIN32OLE_EVENT, "handler=", fev_set_handler, 1);
+ rb_define_method(cWIN32OLE_EVENT, "handler", fev_get_handler, 0);
cWIN32OLE_VARIANT = rb_define_class("WIN32OLE_VARIANT", rb_cObject);
rb_define_alloc_func(cWIN32OLE_VARIANT, folevariant_s_allocate);
diff --git a/test/win32ole/test_win32ole_event.rb b/test/win32ole/test_win32ole_event.rb
index 6ab165bd67..276a018167 100644
--- a/test/win32ole/test_win32ole_event.rb
+++ b/test/win32ole/test_win32ole_event.rb
@@ -6,6 +6,8 @@ require 'test/unit'
if defined?(WIN32OLE_EVENT)
class TestWIN32OLE_EVENT < Test::Unit::TestCase
+ module IE
+ end
def create_temp_html
fso = WIN32OLE.new('Scripting.FileSystemObject')
dummy_file = fso.GetTempName + ".html"
@@ -22,10 +24,18 @@ if defined?(WIN32OLE_EVENT)
sleep 0.1
end
+ def wait_ie
+ while @ie.readyState != IE::READYSTATE_COMPLETE
+ message_loop
+ end
+ end
+
def setup
WIN32OLE_EVENT.message_loop
@ie = WIN32OLE.new("InternetExplorer.Application")
- message_loop
+ if !defined?(IE::READYSTATE_COMPLETE)
+ WIN32OLE.const_load(@ie, IE)
+ end
@ie.visible = true
message_loop
@event = ""
@@ -61,11 +71,7 @@ if defined?(WIN32OLE_EVENT)
ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
ev.on_event {|*args| default_handler(*args)}
@ie.navigate("file:///#{@f}")
- while @ie.busy
- WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
- GC.start
- message_loop
- end
+ wait_ie
assert_match(/BeforeNavigate/, @event)
assert_match(/NavigateComplete/, @event)
end
@@ -75,9 +81,7 @@ if defined?(WIN32OLE_EVENT)
ev.on_event('BeforeNavigate') {|*args| handler1}
ev.on_event('BeforeNavigate') {|*args| handler2}
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal("handler2", @event2)
end
@@ -86,9 +90,7 @@ if defined?(WIN32OLE_EVENT)
ev.on_event {|*args| handler1}
ev.on_event {|*args| handler2}
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal("handler2", @event2)
end
@@ -98,9 +100,7 @@ if defined?(WIN32OLE_EVENT)
ev.on_event{|*args| handler2}
ev.on_event('NavigateComplete'){|*args| handler3(*args)}
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert(@event3!="")
assert("handler2", @event2)
end
@@ -110,9 +110,7 @@ if defined?(WIN32OLE_EVENT)
ev.on_event {|*args| default_handler(*args)}
ev.on_event('NavigateComplete'){|*args| handler3(*args)}
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_match(/BeforeNavigate/, @event)
assert(/NavigateComplete/ !~ @event)
assert(@event!="")
@@ -122,16 +120,12 @@ if defined?(WIN32OLE_EVENT)
ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
ev.on_event {|*args| default_handler(*args)}
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_match(/BeforeNavigate/, @event)
ev.unadvise
@event = ""
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal("", @event);
assert_raise(WIN32OLERuntimeError) {
ev.on_event {|*args| default_handler(*args)}
@@ -158,9 +152,7 @@ if defined?(WIN32OLE_EVENT)
}
bl = @ie.locationURL
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal(bl, @ie.locationURL)
end
@@ -171,9 +163,7 @@ if defined?(WIN32OLE_EVENT)
}
bl = @ie.locationURL
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal(bl, @ie.locationURL)
end
@@ -184,9 +174,7 @@ if defined?(WIN32OLE_EVENT)
}
bl = @ie.locationURL
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal(bl, @ie.locationURL)
end
@@ -197,9 +185,7 @@ if defined?(WIN32OLE_EVENT)
}
bl = @ie.locationURL
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal(bl, @ie.locationURL)
end
@@ -210,9 +196,7 @@ if defined?(WIN32OLE_EVENT)
}
bl = @ie.locationURL
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal(bl, @ie.locationURL)
end
@@ -223,9 +207,7 @@ if defined?(WIN32OLE_EVENT)
}
bl = @ie.locationURL
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
+ wait_ie
assert_equal(bl, @ie.locationURL)
end
@@ -234,10 +216,7 @@ if defined?(WIN32OLE_EVENT)
ev.on_event{handler1}
ev.off_event
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
- WIN32OLE_EVENT.message_loop
+ wait_ie
assert_equal("", @event2)
end
@@ -246,10 +225,7 @@ if defined?(WIN32OLE_EVENT)
ev.on_event('BeforeNavigate2'){handler1}
ev.off_event('BeforeNavigate2')
@ie.navigate("file:///#{@f}")
- while @ie.busy
- message_loop
- end
- WIN32OLE_EVENT.message_loop
+ wait_ie
assert_equal("", @event2)
end
@@ -267,6 +243,7 @@ if defined?(WIN32OLE_EVENT)
def teardown
@ie.quit
+ message_loop
@ie = nil
i = 0
begin
@@ -280,5 +257,58 @@ if defined?(WIN32OLE_EVENT)
GC.start
message_loop
end
+
+ class Handler1
+ attr_reader :val1, :val2, :val3, :val4
+ def initialize
+ @val1 = nil
+ @val2 = nil
+ @val3 = nil
+ @val4 = nil
+ end
+ def onStatusTextChange(t)
+ @val1 = t
+ end
+ def onProgressChange(p, pmax)
+ @val2 = p
+ @val3 = pmax
+ end
+ def onPropertyChange(p)
+ @val4 = p
+ end
+ end
+
+ class Handler2
+ attr_reader :ev
+ def initialize
+ @ev = ""
+ end
+ def method_missing(ev, *arg)
+ @ev += ev
+ end
+ end
+
+ def test_handler1
+ ev = WIN32OLE_EVENT.new(@ie)
+ h1 = Handler1.new
+ ev.handler = h1
+ @ie.navigate("file:///#{@f}")
+ wait_ie
+ assert(h1.val1)
+ assert_equal(h1.val1, ev.handler.val1)
+ assert(h1.val2)
+ assert(h1.val3)
+ assert(h1.val4)
+ end
+
+ def test_handler2
+ ev = WIN32OLE_EVENT.new(@ie)
+ h2 = Handler2.new
+ ev.handler = h2
+ @ie.navigate("file:///#{@f}")
+ wait_ie
+ assert(h2.ev != "")
+ end
+
end
end