summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--ext/win32ole/win32ole.c83
-rw-r--r--test/win32ole/test_win32ole_event.rb83
3 files changed, 167 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index ad442d34a3..b3ee143272 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Sun Jul 13 21:23:08 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (EVENTSINK_Invoke): using hash
+ to set value to the reference argument of event.
+
+ * test/win32ole/test_win32ole_event.rb: ditto.
+
Sun Jul 13 06:57:09 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/pty/pty.c (raise_from_wait, pty_syswait, get_device_once):
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c
index bfefb83e2a..4ee0ed3f7a 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.3"
+#define WIN32OLE_VERSION "1.2.4"
typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
(REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
@@ -499,6 +499,8 @@ 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 void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams);
+static VALUE hash2result(VALUE hash);
static void ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams);
static HRESULT find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo);
static HRESULT find_coclass(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **pTypeInfo2, TYPEATTR **pTypeAttr2);
@@ -7371,6 +7373,44 @@ ole_search_event(VALUE ary, VALUE ev, BOOL *is_default)
return def_event;
}
+static void
+hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams)
+{
+ BSTR *bstrs;
+ HRESULT hr;
+ UINT len, i;
+ VARIANT *pvar;
+ VALUE val;
+ VALUE key;
+ len = 0;
+ bstrs = ALLOCA_N(BSTR, pdispparams->cArgs + 1);
+ hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
+ bstrs, pdispparams->cArgs + 1,
+ &len);
+ if (FAILED(hr))
+ return;
+
+ for (i = 0; i < len - 1; i++) {
+ key = WC2VSTR(bstrs[i + 1]);
+ val = rb_hash_aref(hash, INT2FIX(i));
+ if (val == Qnil)
+ val = rb_hash_aref(hash, key);
+ if (val == Qnil)
+ val = rb_hash_aref(hash, rb_str_intern(key));
+ pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
+ ole_val2ptr_variant(val, pvar);
+ }
+}
+
+static VALUE
+hash2result(VALUE hash)
+{
+ VALUE ret = Qnil;
+ ret = rb_hash_aref(hash, rb_str_new2("return"));
+ if (ret == Qnil)
+ ret = rb_hash_aref(hash, rb_str_intern(rb_str_new2("return")));
+ return ret;
+}
static void
ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams)
@@ -7443,10 +7483,19 @@ STDMETHODIMP EVENTSINK_Invoke(
argv = rb_ary_new();
rb_ary_push(args, argv);
result = rb_apply(handler, rb_intern("call"), args);
- ary2ptr_dispparams(argv, pdispparams);
+ if(TYPE(result) == T_HASH) {
+ hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams);
+ result = hash2result(result);
+ } else {
+ ary2ptr_dispparams(argv, pdispparams);
+ }
}
else {
result = rb_apply(handler, rb_intern("call"), args);
+ if(TYPE(result) == T_HASH) {
+ hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams);
+ result = hash2result(result);
+ }
}
if (pvarResult) {
ole_val2variant(result, pvarResult);
@@ -7829,7 +7878,6 @@ ev_advise(int argc, VALUE *argv, VALUE self)
IEVENTSINKOBJ *pIEV;
DWORD dwCookie;
struct oleeventdata *poleev;
- VALUE events = Qnil;
rb_secure(4);
rb_scan_args(argc, argv, "11", &ole, &itf);
@@ -7966,9 +8014,28 @@ ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
*
* Defines the callback event.
* If argument is omitted, this method defines the callback of all events.
+ * If you want to modify reference argument in callback, return hash in
+ * callback. If you want to return value to OLE server as result of callback
+ * use `return' or :return.
+ *
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
+ * ev = WIN32OLE_EVENT.new(ie)
* ev.on_event("NavigateComplete") {|url| puts url}
+ * ev.on_event() {|ev, *args| puts "#{ev} fired"}
+ *
+ * ev.on_event("BeforeNavigate2") {|*args|
+ * ...
+ * # set true to BeforeNavigate reference argument `Cancel'.
+ * # Cancel is 7-th argument of BeforeNavigate,
+ * # so you can use 6 as key of hash instead of 'Cancel'.
+ * # The argument is counted from 0.
+ * # The hash key of 0 means first argument.)
+ * {:Cancel => true} # or {'Cancel' => true} or {6 => true}
+ * }
+ *
+ * ev.on_event(...) {|*args|
+ * {:return => 1, :xxx => yyy}
+ * }
*/
static VALUE
fev_on_event(int argc, VALUE *argv, VALUE self)
@@ -7982,7 +8049,13 @@ fev_on_event(int argc, VALUE *argv, VALUE self)
*
* Defines the callback of event.
* If you want modify argument in callback,
- * you should use this method instead of WIN32OLE_EVENT#on_event.
+ * you could use this method instead of WIN32OLE_EVENT#on_event.
+ *
+ * ie = WIN32OLE.new('InternetExplorer.Application')
+ * ev = WIN32OLE_EVENT.new(ie)
+ * ev.on_event_with_outargs('BeforeNavigate2') {|*args|
+ * args.last[6] = true
+ * }
*/
static VALUE
fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self)
diff --git a/test/win32ole/test_win32ole_event.rb b/test/win32ole/test_win32ole_event.rb
index 42e80ced90..dafabffc5a 100644
--- a/test/win32ole/test_win32ole_event.rb
+++ b/test/win32ole/test_win32ole_event.rb
@@ -164,6 +164,76 @@ if defined?(WIN32OLE_EVENT)
assert_equal(bl, @ie.locationURL)
end
+ def test_on_event_hash_return
+ ev = WIN32OLE_EVENT.new(@ie)
+ ev.on_event('BeforeNavigate2'){|*args|
+ {:return => 1, :Cancel => true}
+ }
+ bl = @ie.locationURL
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ WIN32OLE_EVENT.message_loop
+ end
+ assert_equal(bl, @ie.locationURL)
+ end
+
+ def test_on_event_hash_return2
+ ev = WIN32OLE_EVENT.new(@ie)
+ ev.on_event('BeforeNavigate2'){|*args|
+ {:Cancel => true}
+ }
+ bl = @ie.locationURL
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ WIN32OLE_EVENT.message_loop
+ end
+ assert_equal(bl, @ie.locationURL)
+ end
+
+ def test_on_event_hash_return3
+ ev = WIN32OLE_EVENT.new(@ie)
+ ev.on_event('BeforeNavigate2'){|*args|
+ {'Cancel' => true}
+ }
+ bl = @ie.locationURL
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ WIN32OLE_EVENT.message_loop
+ end
+ assert_equal(bl, @ie.locationURL)
+ end
+
+ def test_on_event_hash_return4
+ ev = WIN32OLE_EVENT.new(@ie)
+ ev.on_event('BeforeNavigate2'){|*args|
+ {'return' => 2, 'Cancel' => true}
+ }
+ bl = @ie.locationURL
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ WIN32OLE_EVENT.message_loop
+ end
+ assert_equal(bl, @ie.locationURL)
+ end
+
+ def test_on_event_hash_return5
+ ev = WIN32OLE_EVENT.new(@ie)
+ ev.on_event('BeforeNavigate2'){|*args|
+ {6 => true}
+ }
+ bl = @ie.locationURL
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ WIN32OLE_EVENT.message_loop
+ end
+ assert_equal(bl, @ie.locationURL)
+ end
+
def handler1
@event2 = "handler1"
end
@@ -180,8 +250,19 @@ if defined?(WIN32OLE_EVENT)
@ie.quit
WIN32OLE_EVENT.message_loop
@ie = nil
- File.unlink(@f)
+ WIN32OLE_EVENT.message_loop
+ sleep 0.1
+ begin
+ File.unlink(@f)
+ rescue Error::EACCESS
+ WIN32OLE_EVENT.message_loop
+ sleep 0.2
+ File.unlink(@f)
+ end
+
GC.start
+ WIN32OLE_EVENT.message_loop
+ sleep 0.1
end
end
end