win32ole 1.8.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +56 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/ext/win32ole/depend +12 -0
  11. data/ext/win32ole/extconf.rb +45 -0
  12. data/ext/win32ole/sample/excel1.rb +37 -0
  13. data/ext/win32ole/sample/excel2.rb +31 -0
  14. data/ext/win32ole/sample/excel3.rb +21 -0
  15. data/ext/win32ole/sample/ie.rb +12 -0
  16. data/ext/win32ole/sample/ieconst.rb +33 -0
  17. data/ext/win32ole/sample/ienavi.rb +41 -0
  18. data/ext/win32ole/sample/ienavi2.rb +41 -0
  19. data/ext/win32ole/sample/oledirs.rb +24 -0
  20. data/ext/win32ole/sample/olegen.rb +348 -0
  21. data/ext/win32ole/sample/xml.rb +7307 -0
  22. data/ext/win32ole/win32ole.c +4140 -0
  23. data/ext/win32ole/win32ole.h +155 -0
  24. data/ext/win32ole/win32ole_error.c +84 -0
  25. data/ext/win32ole/win32ole_error.h +9 -0
  26. data/ext/win32ole/win32ole_event.c +1277 -0
  27. data/ext/win32ole/win32ole_event.h +6 -0
  28. data/ext/win32ole/win32ole_method.c +950 -0
  29. data/ext/win32ole/win32ole_method.h +16 -0
  30. data/ext/win32ole/win32ole_param.c +438 -0
  31. data/ext/win32ole/win32ole_param.h +8 -0
  32. data/ext/win32ole/win32ole_record.c +604 -0
  33. data/ext/win32ole/win32ole_record.h +10 -0
  34. data/ext/win32ole/win32ole_type.c +915 -0
  35. data/ext/win32ole/win32ole_type.h +8 -0
  36. data/ext/win32ole/win32ole_typelib.c +844 -0
  37. data/ext/win32ole/win32ole_typelib.h +11 -0
  38. data/ext/win32ole/win32ole_variable.c +380 -0
  39. data/ext/win32ole/win32ole_variable.h +8 -0
  40. data/ext/win32ole/win32ole_variant.c +733 -0
  41. data/ext/win32ole/win32ole_variant.h +9 -0
  42. data/ext/win32ole/win32ole_variant_m.c +149 -0
  43. data/ext/win32ole/win32ole_variant_m.h +7 -0
  44. data/lib/win32ole.rb +33 -0
  45. data/lib/win32ole/property.rb +17 -0
  46. data/win32ole.gemspec +22 -0
  47. metadata +91 -0
@@ -0,0 +1,155 @@
1
+ #ifndef WIN32OLE_H
2
+ #define WIN32OLE_H 1
3
+ #include "ruby/ruby.h"
4
+ #include "ruby/st.h"
5
+ #include "ruby/encoding.h"
6
+
7
+ #define GNUC_OLDER_3_4_4 \
8
+ ((__GNUC__ < 3) || \
9
+ ((__GNUC__ <= 3) && (__GNUC_MINOR__ < 4)) || \
10
+ ((__GNUC__ <= 3) && (__GNUC_MINOR__ <= 4) && (__GNUC_PATCHLEVEL__ <= 4)))
11
+
12
+ #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
13
+ #ifndef NONAMELESSUNION
14
+ #define NONAMELESSUNION 1
15
+ #endif
16
+ #endif
17
+
18
+ #include <ctype.h>
19
+
20
+ #include <windows.h>
21
+ #include <ocidl.h>
22
+ #include <olectl.h>
23
+ #include <ole2.h>
24
+ #if defined(HAVE_TYPE_IMULTILANGUAGE2) || defined(HAVE_TYPE_IMULTILANGUAGE)
25
+ #include <mlang.h>
26
+ #endif
27
+ #include <stdlib.h>
28
+ #include <math.h>
29
+ #ifdef HAVE_STDARG_PROTOTYPES
30
+ #include <stdarg.h>
31
+ #define va_init_list(a,b) va_start(a,b)
32
+ #else
33
+ #include <varargs.h>
34
+ #define va_init_list(a,b) va_start(a)
35
+ #endif
36
+ #include <objidl.h>
37
+
38
+ #define DOUT fprintf(stderr,"%s(%d)\n", __FILE__, __LINE__)
39
+ #define DOUTS(x) fprintf(stderr,"%s(%d):" #x "=%s\n",__FILE__, __LINE__,x)
40
+ #define DOUTMSG(x) fprintf(stderr, "%s(%d):" #x "\n",__FILE__, __LINE__)
41
+ #define DOUTI(x) fprintf(stderr, "%s(%d):" #x "=%d\n",__FILE__, __LINE__,x)
42
+ #define DOUTD(x) fprintf(stderr, "%s(%d):" #x "=%f\n",__FILE__, __LINE__,x)
43
+
44
+ #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
45
+ #define V_UNION1(X, Y) ((X)->u.Y)
46
+ #else
47
+ #define V_UNION1(X, Y) ((X)->Y)
48
+ #endif
49
+
50
+ #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
51
+ #undef V_UNION
52
+ #define V_UNION(X,Y) ((X)->n1.n2.n3.Y)
53
+
54
+ #undef V_VT
55
+ #define V_VT(X) ((X)->n1.n2.vt)
56
+
57
+ #undef V_BOOL
58
+ #define V_BOOL(X) V_UNION(X,boolVal)
59
+ #endif
60
+
61
+ #ifndef V_I1REF
62
+ #define V_I1REF(X) V_UNION(X, pcVal)
63
+ #endif
64
+
65
+ #ifndef V_UI2REF
66
+ #define V_UI2REF(X) V_UNION(X, puiVal)
67
+ #endif
68
+
69
+ #ifndef V_INT
70
+ #define V_INT(X) V_UNION(X, intVal)
71
+ #endif
72
+
73
+ #ifndef V_INTREF
74
+ #define V_INTREF(X) V_UNION(X, pintVal)
75
+ #endif
76
+
77
+ #ifndef V_UINT
78
+ #define V_UINT(X) V_UNION(X, uintVal)
79
+ #endif
80
+
81
+ #ifndef V_UINTREF
82
+ #define V_UINTREF(X) V_UNION(X, puintVal)
83
+ #endif
84
+
85
+ #ifdef HAVE_LONG_LONG
86
+ #define I8_2_NUM LL2NUM
87
+ #define UI8_2_NUM ULL2NUM
88
+ #define NUM2I8 RB_NUM2LL
89
+ #define NUM2UI8 RB_NUM2ULL
90
+ #else
91
+ #define I8_2_NUM RB_INT2NUM
92
+ #define UI8_2_NUM RB_UINT2NUM
93
+ #define NUM2I8 RB_NUM2INT
94
+ #define NUM2UI8 RB_NUM2UINT
95
+ #endif
96
+
97
+ #define OLE_ADDREF(X) (X) ? ((X)->lpVtbl->AddRef(X)) : 0
98
+ #define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0
99
+ #define OLE_FREE(x) {\
100
+ if(ole_initialized() == TRUE) {\
101
+ if(x) {\
102
+ OLE_RELEASE(x);\
103
+ (x) = 0;\
104
+ }\
105
+ }\
106
+ }
107
+
108
+ #define OLE_GET_TYPEATTR(X, Y) ((X)->lpVtbl->GetTypeAttr((X), (Y)))
109
+ #define OLE_RELEASE_TYPEATTR(X, Y) ((X)->lpVtbl->ReleaseTypeAttr((X), (Y)))
110
+
111
+ struct oledata {
112
+ IDispatch *pDispatch;
113
+ };
114
+
115
+ VALUE cWIN32OLE;
116
+ LCID cWIN32OLE_lcid;
117
+
118
+ struct oledata *oledata_get_struct(VALUE obj);
119
+ LPWSTR ole_vstr2wc(VALUE vstr);
120
+ LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey);
121
+ LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey);
122
+ VALUE reg_enum_key(HKEY hkey, DWORD i);
123
+ VALUE reg_get_val(HKEY hkey, const char *subkey);
124
+ VALUE reg_get_val2(HKEY hkey, const char *subkey);
125
+ void ole_initialize(void);
126
+ VALUE default_inspect(VALUE self, const char *class_name);
127
+ char *ole_wc2mb(LPWSTR pw);
128
+ VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree);
129
+
130
+ #define WC2VSTR(x) ole_wc2vstr((x), TRUE)
131
+
132
+ BOOL ole_initialized(void);
133
+ HRESULT ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile);
134
+ VALUE ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
135
+ VALUE make_inspect(const char *class_name, VALUE detail);
136
+ void ole_val2variant(VALUE val, VARIANT *var);
137
+ void ole_val2variant2(VALUE val, VARIANT *var);
138
+ void ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt);
139
+ VALUE ole_variant2val(VARIANT *pvar);
140
+ HRESULT ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt);
141
+ VOID *val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt);
142
+ HRESULT typelib_from_val(VALUE obj, ITypeLib **pTypeLib);
143
+
144
+ #include "win32ole_variant_m.h"
145
+ #include "win32ole_typelib.h"
146
+ #include "win32ole_type.h"
147
+ #include "win32ole_variable.h"
148
+ #include "win32ole_method.h"
149
+ #include "win32ole_param.h"
150
+ #include "win32ole_event.h"
151
+ #include "win32ole_variant.h"
152
+ #include "win32ole_record.h"
153
+ #include "win32ole_error.h"
154
+
155
+ #endif
@@ -0,0 +1,84 @@
1
+ #include "win32ole.h"
2
+
3
+ static VALUE ole_hresult2msg(HRESULT hr);
4
+
5
+ static VALUE
6
+ ole_hresult2msg(HRESULT hr)
7
+ {
8
+ VALUE msg = Qnil;
9
+ char *p_msg = NULL;
10
+ char *term = NULL;
11
+ DWORD dwCount;
12
+
13
+ char strhr[100];
14
+ sprintf(strhr, " HRESULT error code:0x%08x\n ", (unsigned)hr);
15
+ msg = rb_str_new2(strhr);
16
+ dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
17
+ FORMAT_MESSAGE_FROM_SYSTEM |
18
+ FORMAT_MESSAGE_IGNORE_INSERTS,
19
+ NULL, hr,
20
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
21
+ (LPTSTR)&p_msg, 0, NULL);
22
+ if (dwCount == 0) {
23
+ dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
24
+ FORMAT_MESSAGE_FROM_SYSTEM |
25
+ FORMAT_MESSAGE_IGNORE_INSERTS,
26
+ NULL, hr, cWIN32OLE_lcid,
27
+ (LPTSTR)&p_msg, 0, NULL);
28
+ }
29
+ if (dwCount > 0) {
30
+ term = p_msg + strlen(p_msg);
31
+ while (p_msg < term) {
32
+ term--;
33
+ if (*term == '\r' || *term == '\n')
34
+ *term = '\0';
35
+ else break;
36
+ }
37
+ if (p_msg[0] != '\0') {
38
+ rb_str_cat2(msg, p_msg);
39
+ }
40
+ }
41
+ LocalFree(p_msg);
42
+ return msg;
43
+ }
44
+
45
+ void
46
+ ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...)
47
+ {
48
+ va_list args;
49
+ VALUE msg;
50
+ VALUE err_msg;
51
+ va_init_list(args, fmt);
52
+ msg = rb_vsprintf(fmt, args);
53
+ va_end(args);
54
+
55
+ err_msg = ole_hresult2msg(hr);
56
+ if(err_msg != Qnil) {
57
+ rb_str_cat2(msg, "\n");
58
+ rb_str_append(msg, err_msg);
59
+ }
60
+ rb_exc_raise(rb_exc_new_str(ecs, msg));
61
+ }
62
+
63
+ void
64
+ Init_win32ole_error(void)
65
+ {
66
+ /*
67
+ * Document-class: WIN32OLERuntimeError
68
+ *
69
+ * Raised when OLE processing failed.
70
+ *
71
+ * EX:
72
+ *
73
+ * obj = WIN32OLE.new("NonExistProgID")
74
+ *
75
+ * raises the exception:
76
+ *
77
+ * WIN32OLERuntimeError: unknown OLE server: `NonExistProgID'
78
+ * HRESULT error code:0x800401f3
79
+ * Invalid class string
80
+ *
81
+ */
82
+ eWIN32OLERuntimeError = rb_define_class("WIN32OLERuntimeError", rb_eRuntimeError);
83
+ eWIN32OLEQueryInterfaceError = rb_define_class("WIN32OLEQueryInterfaceError", eWIN32OLERuntimeError);
84
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef WIN32OLE_ERROR_H
2
+ #define WIN32OLE_ERROR_H 1
3
+
4
+ VALUE eWIN32OLERuntimeError;
5
+ VALUE eWIN32OLEQueryInterfaceError;
6
+ NORETURN(PRINTF_ARGS(void ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...), 3, 4));
7
+ void Init_win32ole_error(void);
8
+
9
+ #endif
@@ -0,0 +1,1277 @@
1
+ #include "win32ole.h"
2
+
3
+ /*
4
+ * Document-class: WIN32OLE_EVENT
5
+ *
6
+ * <code>WIN32OLE_EVENT</code> objects controls OLE event.
7
+ */
8
+
9
+ RUBY_EXTERN void rb_write_error_str(VALUE mesg);
10
+
11
+ typedef struct {
12
+ struct IEventSinkVtbl * lpVtbl;
13
+ } IEventSink, *PEVENTSINK;
14
+
15
+ typedef struct IEventSinkVtbl IEventSinkVtbl;
16
+
17
+ struct IEventSinkVtbl {
18
+ STDMETHOD(QueryInterface)(
19
+ PEVENTSINK,
20
+ REFIID,
21
+ LPVOID *);
22
+ STDMETHOD_(ULONG, AddRef)(PEVENTSINK);
23
+ STDMETHOD_(ULONG, Release)(PEVENTSINK);
24
+
25
+ STDMETHOD(GetTypeInfoCount)(
26
+ PEVENTSINK,
27
+ UINT *);
28
+ STDMETHOD(GetTypeInfo)(
29
+ PEVENTSINK,
30
+ UINT,
31
+ LCID,
32
+ ITypeInfo **);
33
+ STDMETHOD(GetIDsOfNames)(
34
+ PEVENTSINK,
35
+ REFIID,
36
+ OLECHAR **,
37
+ UINT,
38
+ LCID,
39
+ DISPID *);
40
+ STDMETHOD(Invoke)(
41
+ PEVENTSINK,
42
+ DISPID,
43
+ REFIID,
44
+ LCID,
45
+ WORD,
46
+ DISPPARAMS *,
47
+ VARIANT *,
48
+ EXCEPINFO *,
49
+ UINT *);
50
+ };
51
+
52
+ typedef struct tagIEVENTSINKOBJ {
53
+ const IEventSinkVtbl *lpVtbl;
54
+ DWORD m_cRef;
55
+ IID m_iid;
56
+ long m_event_id;
57
+ ITypeInfo *pTypeInfo;
58
+ }IEVENTSINKOBJ, *PIEVENTSINKOBJ;
59
+
60
+ struct oleeventdata {
61
+ DWORD dwCookie;
62
+ IConnectionPoint *pConnectionPoint;
63
+ IDispatch *pDispatch;
64
+ long event_id;
65
+ };
66
+
67
+ static VALUE ary_ole_event;
68
+ static ID id_events;
69
+
70
+ VALUE cWIN32OLE_EVENT;
71
+
72
+ STDMETHODIMP EVENTSINK_QueryInterface(PEVENTSINK, REFIID, LPVOID*);
73
+ STDMETHODIMP_(ULONG) EVENTSINK_AddRef(PEVENTSINK);
74
+ STDMETHODIMP_(ULONG) EVENTSINK_Release(PEVENTSINK);
75
+ STDMETHODIMP EVENTSINK_GetTypeInfoCount(PEVENTSINK, UINT*);
76
+ STDMETHODIMP EVENTSINK_GetTypeInfo(PEVENTSINK, UINT, LCID, ITypeInfo**);
77
+ STDMETHODIMP EVENTSINK_GetIDsOfNames(PEVENTSINK, REFIID, OLECHAR**, UINT, LCID, DISPID*);
78
+ STDMETHODIMP EVENTSINK_Invoke(PEVENTSINK, DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*);
79
+
80
+ static const IEventSinkVtbl vtEventSink = {
81
+ EVENTSINK_QueryInterface,
82
+ EVENTSINK_AddRef,
83
+ EVENTSINK_Release,
84
+ EVENTSINK_GetTypeInfoCount,
85
+ EVENTSINK_GetTypeInfo,
86
+ EVENTSINK_GetIDsOfNames,
87
+ EVENTSINK_Invoke,
88
+ };
89
+
90
+ void EVENTSINK_Destructor(PIEVENTSINKOBJ);
91
+ static void ole_val2ptr_variant(VALUE val, VARIANT *var);
92
+ static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams);
93
+ static VALUE hash2result(VALUE hash);
94
+ static void ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams);
95
+ static VALUE exec_callback(VALUE arg);
96
+ static VALUE rescue_callback(VALUE arg);
97
+ static HRESULT find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo);
98
+ static HRESULT find_coclass(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **pTypeInfo2, TYPEATTR **pTypeAttr2);
99
+ static HRESULT find_default_source_from_typeinfo(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **ppTypeInfo);
100
+ static HRESULT find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo);
101
+ static long ole_search_event_at(VALUE ary, VALUE ev);
102
+ static VALUE ole_search_event(VALUE ary, VALUE ev, BOOL *is_default);
103
+ static VALUE ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler);
104
+ static void ole_delete_event(VALUE ary, VALUE ev);
105
+ static void oleevent_free(void *ptr);
106
+ static size_t oleevent_size(const void *ptr);
107
+ static VALUE fev_s_allocate(VALUE klass);
108
+ static VALUE ev_advise(int argc, VALUE *argv, VALUE self);
109
+ static VALUE fev_initialize(int argc, VALUE *argv, VALUE self);
110
+ static void ole_msg_loop(void);
111
+ static VALUE fev_s_msg_loop(VALUE klass);
112
+ static void add_event_call_back(VALUE obj, VALUE event, VALUE data);
113
+ static VALUE ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg);
114
+ static VALUE fev_on_event(int argc, VALUE *argv, VALUE self);
115
+ static VALUE fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self);
116
+ static VALUE fev_off_event(int argc, VALUE *argv, VALUE self);
117
+ static VALUE fev_unadvise(VALUE self);
118
+ static VALUE fev_set_handler(VALUE self, VALUE val);
119
+ static VALUE fev_get_handler(VALUE self);
120
+ static VALUE evs_push(VALUE ev);
121
+ static VALUE evs_delete(long i);
122
+ static VALUE evs_entry(long i);
123
+ static long evs_length(void);
124
+
125
+
126
+ static const rb_data_type_t oleevent_datatype = {
127
+ "win32ole_event",
128
+ {NULL, oleevent_free, oleevent_size,},
129
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
130
+ };
131
+
132
+ STDMETHODIMP EVENTSINK_Invoke(
133
+ PEVENTSINK pEventSink,
134
+ DISPID dispid,
135
+ REFIID riid,
136
+ LCID lcid,
137
+ WORD wFlags,
138
+ DISPPARAMS *pdispparams,
139
+ VARIANT *pvarResult,
140
+ EXCEPINFO *pexcepinfo,
141
+ UINT *puArgErr
142
+ ) {
143
+
144
+ HRESULT hr;
145
+ BSTR bstr;
146
+ unsigned int count;
147
+ unsigned int i;
148
+ ITypeInfo *pTypeInfo;
149
+ VARIANT *pvar;
150
+ VALUE ary, obj, event, args, outargv, ev, result;
151
+ VALUE handler = Qnil;
152
+ VALUE arg[3];
153
+ VALUE mid;
154
+ VALUE is_outarg = Qfalse;
155
+ BOOL is_default_handler = FALSE;
156
+ int state;
157
+
158
+ PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
159
+ pTypeInfo = pEV->pTypeInfo;
160
+ obj = evs_entry(pEV->m_event_id);
161
+ if (!rb_obj_is_kind_of(obj, cWIN32OLE_EVENT)) {
162
+ return NOERROR;
163
+ }
164
+
165
+ ary = rb_ivar_get(obj, id_events);
166
+ if (NIL_P(ary) || !RB_TYPE_P(ary, T_ARRAY)) {
167
+ return NOERROR;
168
+ }
169
+ hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
170
+ &bstr, 1, &count);
171
+ if (FAILED(hr)) {
172
+ return NOERROR;
173
+ }
174
+ ev = WC2VSTR(bstr);
175
+ event = ole_search_event(ary, ev, &is_default_handler);
176
+ if (RB_TYPE_P(event, T_ARRAY)) {
177
+ handler = rb_ary_entry(event, 0);
178
+ mid = rb_intern("call");
179
+ is_outarg = rb_ary_entry(event, 3);
180
+ } else {
181
+ handler = rb_ivar_get(obj, rb_intern("handler"));
182
+ if (handler == Qnil) {
183
+ return NOERROR;
184
+ }
185
+ mid = ole_search_handler_method(handler, ev, &is_default_handler);
186
+ }
187
+ if (handler == Qnil || mid == Qnil) {
188
+ return NOERROR;
189
+ }
190
+
191
+ args = rb_ary_new();
192
+ if (is_default_handler) {
193
+ rb_ary_push(args, ev);
194
+ }
195
+
196
+ /* make argument of event handler */
197
+ for (i = 0; i < pdispparams->cArgs; ++i) {
198
+ pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
199
+ rb_ary_push(args, ole_variant2val(pvar));
200
+ }
201
+ outargv = Qnil;
202
+ if (is_outarg == Qtrue) {
203
+ outargv = rb_ary_new();
204
+ rb_ary_push(args, outargv);
205
+ }
206
+
207
+ /*
208
+ * if exception raised in event callback,
209
+ * then you receive cfp consistency error.
210
+ * to avoid this error we use begin rescue end.
211
+ * and the exception raised then error message print
212
+ * and exit ruby process by Win32OLE itself.
213
+ */
214
+ arg[0] = handler;
215
+ arg[1] = mid;
216
+ arg[2] = args;
217
+ result = rb_protect(exec_callback, (VALUE)arg, &state);
218
+ if (state != 0) {
219
+ rescue_callback(Qnil);
220
+ }
221
+ if(RB_TYPE_P(result, T_HASH)) {
222
+ hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams);
223
+ result = hash2result(result);
224
+ }else if (is_outarg == Qtrue && RB_TYPE_P(outargv, T_ARRAY)) {
225
+ ary2ptr_dispparams(outargv, pdispparams);
226
+ }
227
+
228
+ if (pvarResult) {
229
+ VariantInit(pvarResult);
230
+ ole_val2variant(result, pvarResult);
231
+ }
232
+
233
+ return NOERROR;
234
+ }
235
+
236
+ STDMETHODIMP
237
+ EVENTSINK_QueryInterface(
238
+ PEVENTSINK pEV,
239
+ REFIID iid,
240
+ LPVOID* ppv
241
+ ) {
242
+ if (IsEqualIID(iid, &IID_IUnknown) ||
243
+ IsEqualIID(iid, &IID_IDispatch) ||
244
+ IsEqualIID(iid, &((PIEVENTSINKOBJ)pEV)->m_iid)) {
245
+ *ppv = pEV;
246
+ }
247
+ else {
248
+ *ppv = NULL;
249
+ return E_NOINTERFACE;
250
+ }
251
+ ((LPUNKNOWN)*ppv)->lpVtbl->AddRef((LPUNKNOWN)*ppv);
252
+ return NOERROR;
253
+ }
254
+
255
+ STDMETHODIMP_(ULONG)
256
+ EVENTSINK_AddRef(
257
+ PEVENTSINK pEV
258
+ ){
259
+ PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
260
+ return ++pEVObj->m_cRef;
261
+ }
262
+
263
+ STDMETHODIMP_(ULONG) EVENTSINK_Release(
264
+ PEVENTSINK pEV
265
+ ) {
266
+ PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
267
+ --pEVObj->m_cRef;
268
+ if(pEVObj->m_cRef != 0)
269
+ return pEVObj->m_cRef;
270
+ EVENTSINK_Destructor(pEVObj);
271
+ return 0;
272
+ }
273
+
274
+ STDMETHODIMP EVENTSINK_GetTypeInfoCount(
275
+ PEVENTSINK pEV,
276
+ UINT *pct
277
+ ) {
278
+ *pct = 0;
279
+ return NOERROR;
280
+ }
281
+
282
+ STDMETHODIMP EVENTSINK_GetTypeInfo(
283
+ PEVENTSINK pEV,
284
+ UINT info,
285
+ LCID lcid,
286
+ ITypeInfo **pInfo
287
+ ) {
288
+ *pInfo = NULL;
289
+ return DISP_E_BADINDEX;
290
+ }
291
+
292
+ STDMETHODIMP EVENTSINK_GetIDsOfNames(
293
+ PEVENTSINK pEventSink,
294
+ REFIID riid,
295
+ OLECHAR **szNames,
296
+ UINT cNames,
297
+ LCID lcid,
298
+ DISPID *pDispID
299
+ ) {
300
+ ITypeInfo *pTypeInfo;
301
+ PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
302
+ pTypeInfo = pEV->pTypeInfo;
303
+ if (pTypeInfo) {
304
+ return pTypeInfo->lpVtbl->GetIDsOfNames(pTypeInfo, szNames, cNames, pDispID);
305
+ }
306
+ return DISP_E_UNKNOWNNAME;
307
+ }
308
+
309
+ PIEVENTSINKOBJ
310
+ EVENTSINK_Constructor(void)
311
+ {
312
+ PIEVENTSINKOBJ pEv;
313
+ pEv = ALLOC_N(IEVENTSINKOBJ, 1);
314
+ if(pEv == NULL) return NULL;
315
+ pEv->lpVtbl = &vtEventSink;
316
+ pEv->m_cRef = 0;
317
+ pEv->m_event_id = 0;
318
+ pEv->pTypeInfo = NULL;
319
+ return pEv;
320
+ }
321
+
322
+ void
323
+ EVENTSINK_Destructor(
324
+ PIEVENTSINKOBJ pEVObj
325
+ ) {
326
+ if(pEVObj != NULL) {
327
+ OLE_RELEASE(pEVObj->pTypeInfo);
328
+ free(pEVObj);
329
+ pEVObj = NULL;
330
+ }
331
+ }
332
+
333
+ static void
334
+ ole_val2ptr_variant(VALUE val, VARIANT *var)
335
+ {
336
+ switch (TYPE(val)) {
337
+ case T_STRING:
338
+ if (V_VT(var) == (VT_BSTR | VT_BYREF)) {
339
+ *V_BSTRREF(var) = ole_vstr2wc(val);
340
+ }
341
+ break;
342
+ case T_FIXNUM:
343
+ switch(V_VT(var)) {
344
+ case (VT_UI1 | VT_BYREF) :
345
+ *V_UI1REF(var) = RB_NUM2CHR(val);
346
+ break;
347
+ case (VT_I2 | VT_BYREF) :
348
+ *V_I2REF(var) = (short)RB_NUM2INT(val);
349
+ break;
350
+ case (VT_I4 | VT_BYREF) :
351
+ *V_I4REF(var) = RB_NUM2INT(val);
352
+ break;
353
+ case (VT_R4 | VT_BYREF) :
354
+ *V_R4REF(var) = (float)RB_NUM2INT(val);
355
+ break;
356
+ case (VT_R8 | VT_BYREF) :
357
+ *V_R8REF(var) = RB_NUM2INT(val);
358
+ break;
359
+ default:
360
+ break;
361
+ }
362
+ break;
363
+ case T_FLOAT:
364
+ switch(V_VT(var)) {
365
+ case (VT_I2 | VT_BYREF) :
366
+ *V_I2REF(var) = (short)RB_NUM2INT(val);
367
+ break;
368
+ case (VT_I4 | VT_BYREF) :
369
+ *V_I4REF(var) = RB_NUM2INT(val);
370
+ break;
371
+ case (VT_R4 | VT_BYREF) :
372
+ *V_R4REF(var) = (float)NUM2DBL(val);
373
+ break;
374
+ case (VT_R8 | VT_BYREF) :
375
+ *V_R8REF(var) = NUM2DBL(val);
376
+ break;
377
+ default:
378
+ break;
379
+ }
380
+ break;
381
+ case T_BIGNUM:
382
+ if (V_VT(var) == (VT_R8 | VT_BYREF)) {
383
+ *V_R8REF(var) = rb_big2dbl(val);
384
+ }
385
+ break;
386
+ case T_TRUE:
387
+ if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
388
+ *V_BOOLREF(var) = VARIANT_TRUE;
389
+ }
390
+ break;
391
+ case T_FALSE:
392
+ if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
393
+ *V_BOOLREF(var) = VARIANT_FALSE;
394
+ }
395
+ break;
396
+ default:
397
+ break;
398
+ }
399
+ }
400
+
401
+ static void
402
+ hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams)
403
+ {
404
+ BSTR *bstrs;
405
+ HRESULT hr;
406
+ UINT len, i;
407
+ VARIANT *pvar;
408
+ VALUE val;
409
+ VALUE key;
410
+ len = 0;
411
+ bstrs = ALLOCA_N(BSTR, pdispparams->cArgs + 1);
412
+ hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
413
+ bstrs, pdispparams->cArgs + 1,
414
+ &len);
415
+ if (FAILED(hr))
416
+ return;
417
+
418
+ for (i = 0; i < len - 1; i++) {
419
+ key = WC2VSTR(bstrs[i + 1]);
420
+ val = rb_hash_aref(hash, RB_UINT2NUM(i));
421
+ if (val == Qnil)
422
+ val = rb_hash_aref(hash, key);
423
+ if (val == Qnil)
424
+ val = rb_hash_aref(hash, rb_str_intern(key));
425
+ pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
426
+ ole_val2ptr_variant(val, pvar);
427
+ }
428
+ }
429
+
430
+ static VALUE
431
+ hash2result(VALUE hash)
432
+ {
433
+ VALUE ret = Qnil;
434
+ ret = rb_hash_aref(hash, rb_str_new2("return"));
435
+ if (ret == Qnil)
436
+ ret = rb_hash_aref(hash, rb_str_intern(rb_str_new2("return")));
437
+ return ret;
438
+ }
439
+
440
+ static void
441
+ ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams)
442
+ {
443
+ int i;
444
+ VALUE v;
445
+ VARIANT *pvar;
446
+ for(i = 0; i < RARRAY_LEN(ary) && (unsigned int) i < pdispparams->cArgs; i++) {
447
+ v = rb_ary_entry(ary, i);
448
+ pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
449
+ ole_val2ptr_variant(v, pvar);
450
+ }
451
+ }
452
+
453
+ static VALUE
454
+ exec_callback(VALUE arg)
455
+ {
456
+ VALUE *parg = (VALUE *)arg;
457
+ VALUE handler = parg[0];
458
+ VALUE mid = parg[1];
459
+ VALUE args = parg[2];
460
+ return rb_apply(handler, mid, args);
461
+ }
462
+
463
+ static VALUE
464
+ rescue_callback(VALUE arg)
465
+ {
466
+
467
+ VALUE error;
468
+ VALUE e = rb_errinfo();
469
+ VALUE bt = rb_funcall(e, rb_intern("backtrace"), 0);
470
+ VALUE msg = rb_funcall(e, rb_intern("message"), 0);
471
+ bt = rb_ary_entry(bt, 0);
472
+ error = rb_sprintf("%"PRIsVALUE": %"PRIsVALUE" (%s)\n", bt, msg, rb_obj_classname(e));
473
+ rb_write_error_str(error);
474
+ rb_backtrace();
475
+ ruby_finalize();
476
+ exit(-1);
477
+
478
+ return Qnil;
479
+ }
480
+
481
+ static HRESULT
482
+ find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo)
483
+ {
484
+ HRESULT hr;
485
+ IDispatch *pDispatch;
486
+ ITypeInfo *pTypeInfo;
487
+ ITypeLib *pTypeLib;
488
+ TYPEATTR *pTypeAttr;
489
+ HREFTYPE RefType;
490
+ ITypeInfo *pImplTypeInfo;
491
+ TYPEATTR *pImplTypeAttr;
492
+
493
+ struct oledata *pole = NULL;
494
+ unsigned int index;
495
+ unsigned int count;
496
+ int type;
497
+ BSTR bstr;
498
+ char *pstr;
499
+
500
+ BOOL is_found = FALSE;
501
+ LCID lcid = cWIN32OLE_lcid;
502
+
503
+ pole = oledata_get_struct(ole);
504
+
505
+ pDispatch = pole->pDispatch;
506
+
507
+ hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo);
508
+ if (FAILED(hr))
509
+ return hr;
510
+
511
+ hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo,
512
+ &pTypeLib,
513
+ &index);
514
+ OLE_RELEASE(pTypeInfo);
515
+ if (FAILED(hr))
516
+ return hr;
517
+
518
+ if (!pitf) {
519
+ hr = pTypeLib->lpVtbl->GetTypeInfoOfGuid(pTypeLib,
520
+ piid,
521
+ ppTypeInfo);
522
+ OLE_RELEASE(pTypeLib);
523
+ return hr;
524
+ }
525
+ count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
526
+ for (index = 0; index < count; index++) {
527
+ hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib,
528
+ index,
529
+ &pTypeInfo);
530
+ if (FAILED(hr))
531
+ break;
532
+ hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
533
+
534
+ if(FAILED(hr)) {
535
+ OLE_RELEASE(pTypeInfo);
536
+ break;
537
+ }
538
+ if(pTypeAttr->typekind == TKIND_COCLASS) {
539
+ for (type = 0; type < pTypeAttr->cImplTypes; type++) {
540
+ hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
541
+ type,
542
+ &RefType);
543
+ if (FAILED(hr))
544
+ break;
545
+ hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
546
+ RefType,
547
+ &pImplTypeInfo);
548
+ if (FAILED(hr))
549
+ break;
550
+
551
+ hr = pImplTypeInfo->lpVtbl->GetDocumentation(pImplTypeInfo,
552
+ -1,
553
+ &bstr,
554
+ NULL, NULL, NULL);
555
+ if (FAILED(hr)) {
556
+ OLE_RELEASE(pImplTypeInfo);
557
+ break;
558
+ }
559
+ pstr = ole_wc2mb(bstr);
560
+ if (strcmp(pitf, pstr) == 0) {
561
+ hr = pImplTypeInfo->lpVtbl->GetTypeAttr(pImplTypeInfo,
562
+ &pImplTypeAttr);
563
+ if (SUCCEEDED(hr)) {
564
+ is_found = TRUE;
565
+ *piid = pImplTypeAttr->guid;
566
+ if (ppTypeInfo) {
567
+ *ppTypeInfo = pImplTypeInfo;
568
+ (*ppTypeInfo)->lpVtbl->AddRef((*ppTypeInfo));
569
+ }
570
+ pImplTypeInfo->lpVtbl->ReleaseTypeAttr(pImplTypeInfo,
571
+ pImplTypeAttr);
572
+ }
573
+ }
574
+ free(pstr);
575
+ OLE_RELEASE(pImplTypeInfo);
576
+ if (is_found || FAILED(hr))
577
+ break;
578
+ }
579
+ }
580
+
581
+ OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
582
+ OLE_RELEASE(pTypeInfo);
583
+ if (is_found || FAILED(hr))
584
+ break;
585
+ }
586
+ OLE_RELEASE(pTypeLib);
587
+ if(!is_found)
588
+ return E_NOINTERFACE;
589
+ return hr;
590
+ }
591
+
592
+ static HRESULT
593
+ find_coclass(
594
+ ITypeInfo *pTypeInfo,
595
+ TYPEATTR *pTypeAttr,
596
+ ITypeInfo **pCOTypeInfo,
597
+ TYPEATTR **pCOTypeAttr)
598
+ {
599
+ HRESULT hr = E_NOINTERFACE;
600
+ ITypeLib *pTypeLib;
601
+ int count;
602
+ BOOL found = FALSE;
603
+ ITypeInfo *pTypeInfo2;
604
+ TYPEATTR *pTypeAttr2;
605
+ int flags;
606
+ int i,j;
607
+ HREFTYPE href;
608
+ ITypeInfo *pRefTypeInfo;
609
+ TYPEATTR *pRefTypeAttr;
610
+
611
+ hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, NULL);
612
+ if (FAILED(hr)) {
613
+ return hr;
614
+ }
615
+ count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
616
+ for (i = 0; i < count && !found; i++) {
617
+ hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo2);
618
+ if (FAILED(hr))
619
+ continue;
620
+ hr = OLE_GET_TYPEATTR(pTypeInfo2, &pTypeAttr2);
621
+ if (FAILED(hr)) {
622
+ OLE_RELEASE(pTypeInfo2);
623
+ continue;
624
+ }
625
+ if (pTypeAttr2->typekind != TKIND_COCLASS) {
626
+ OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
627
+ OLE_RELEASE(pTypeInfo2);
628
+ continue;
629
+ }
630
+ for (j = 0; j < pTypeAttr2->cImplTypes && !found; j++) {
631
+ hr = pTypeInfo2->lpVtbl->GetImplTypeFlags(pTypeInfo2, j, &flags);
632
+ if (FAILED(hr))
633
+ continue;
634
+ if (!(flags & IMPLTYPEFLAG_FDEFAULT))
635
+ continue;
636
+ hr = pTypeInfo2->lpVtbl->GetRefTypeOfImplType(pTypeInfo2, j, &href);
637
+ if (FAILED(hr))
638
+ continue;
639
+ hr = pTypeInfo2->lpVtbl->GetRefTypeInfo(pTypeInfo2, href, &pRefTypeInfo);
640
+ if (FAILED(hr))
641
+ continue;
642
+ hr = OLE_GET_TYPEATTR(pRefTypeInfo, &pRefTypeAttr);
643
+ if (FAILED(hr)) {
644
+ OLE_RELEASE(pRefTypeInfo);
645
+ continue;
646
+ }
647
+ if (IsEqualGUID(&(pTypeAttr->guid), &(pRefTypeAttr->guid))) {
648
+ found = TRUE;
649
+ }
650
+ }
651
+ if (!found) {
652
+ OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
653
+ OLE_RELEASE(pTypeInfo2);
654
+ }
655
+ }
656
+ OLE_RELEASE(pTypeLib);
657
+ if (found) {
658
+ *pCOTypeInfo = pTypeInfo2;
659
+ *pCOTypeAttr = pTypeAttr2;
660
+ hr = S_OK;
661
+ } else {
662
+ hr = E_NOINTERFACE;
663
+ }
664
+ return hr;
665
+ }
666
+
667
+ static HRESULT
668
+ find_default_source_from_typeinfo(
669
+ ITypeInfo *pTypeInfo,
670
+ TYPEATTR *pTypeAttr,
671
+ ITypeInfo **ppTypeInfo)
672
+ {
673
+ int i = 0;
674
+ HRESULT hr = E_NOINTERFACE;
675
+ int flags;
676
+ HREFTYPE hRefType;
677
+ /* Enumerate all implemented types of the COCLASS */
678
+ for (i = 0; i < pTypeAttr->cImplTypes; i++) {
679
+ hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
680
+ if (FAILED(hr))
681
+ continue;
682
+
683
+ /*
684
+ looking for the [default] [source]
685
+ we just hope that it is a dispinterface :-)
686
+ */
687
+ if ((flags & IMPLTYPEFLAG_FDEFAULT) &&
688
+ (flags & IMPLTYPEFLAG_FSOURCE)) {
689
+
690
+ hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
691
+ i, &hRefType);
692
+ if (FAILED(hr))
693
+ continue;
694
+ hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
695
+ hRefType, ppTypeInfo);
696
+ if (SUCCEEDED(hr))
697
+ break;
698
+ }
699
+ }
700
+ return hr;
701
+ }
702
+
703
+ static HRESULT
704
+ find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo)
705
+ {
706
+ HRESULT hr;
707
+ IProvideClassInfo2 *pProvideClassInfo2;
708
+ IProvideClassInfo *pProvideClassInfo;
709
+ void *p;
710
+
711
+ IDispatch *pDispatch;
712
+ ITypeInfo *pTypeInfo;
713
+ ITypeInfo *pTypeInfo2 = NULL;
714
+ TYPEATTR *pTypeAttr;
715
+ TYPEATTR *pTypeAttr2 = NULL;
716
+
717
+ struct oledata *pole = NULL;
718
+
719
+ pole = oledata_get_struct(ole);
720
+ pDispatch = pole->pDispatch;
721
+ hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
722
+ &IID_IProvideClassInfo2,
723
+ &p);
724
+ if (SUCCEEDED(hr)) {
725
+ pProvideClassInfo2 = p;
726
+ hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2,
727
+ GUIDKIND_DEFAULT_SOURCE_DISP_IID,
728
+ piid);
729
+ OLE_RELEASE(pProvideClassInfo2);
730
+ if (SUCCEEDED(hr)) {
731
+ hr = find_iid(ole, NULL, piid, ppTypeInfo);
732
+ }
733
+ }
734
+ if (SUCCEEDED(hr)) {
735
+ return hr;
736
+ }
737
+ hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
738
+ &IID_IProvideClassInfo,
739
+ &p);
740
+ if (SUCCEEDED(hr)) {
741
+ pProvideClassInfo = p;
742
+ hr = pProvideClassInfo->lpVtbl->GetClassInfo(pProvideClassInfo,
743
+ &pTypeInfo);
744
+ OLE_RELEASE(pProvideClassInfo);
745
+ }
746
+ if (FAILED(hr)) {
747
+ hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, cWIN32OLE_lcid, &pTypeInfo );
748
+ }
749
+ if (FAILED(hr))
750
+ return hr;
751
+ hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
752
+ if (FAILED(hr)) {
753
+ OLE_RELEASE(pTypeInfo);
754
+ return hr;
755
+ }
756
+
757
+ *ppTypeInfo = 0;
758
+ hr = find_default_source_from_typeinfo(pTypeInfo, pTypeAttr, ppTypeInfo);
759
+ if (!*ppTypeInfo) {
760
+ hr = find_coclass(pTypeInfo, pTypeAttr, &pTypeInfo2, &pTypeAttr2);
761
+ if (SUCCEEDED(hr)) {
762
+ hr = find_default_source_from_typeinfo(pTypeInfo2, pTypeAttr2, ppTypeInfo);
763
+ OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
764
+ OLE_RELEASE(pTypeInfo2);
765
+ }
766
+ }
767
+ OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
768
+ OLE_RELEASE(pTypeInfo);
769
+ /* Now that would be a bad surprise, if we didn't find it, wouldn't it? */
770
+ if (!*ppTypeInfo) {
771
+ if (SUCCEEDED(hr))
772
+ hr = E_UNEXPECTED;
773
+ return hr;
774
+ }
775
+
776
+ /* Determine IID of default source interface */
777
+ hr = (*ppTypeInfo)->lpVtbl->GetTypeAttr(*ppTypeInfo, &pTypeAttr);
778
+ if (SUCCEEDED(hr)) {
779
+ *piid = pTypeAttr->guid;
780
+ (*ppTypeInfo)->lpVtbl->ReleaseTypeAttr(*ppTypeInfo, pTypeAttr);
781
+ }
782
+ else
783
+ OLE_RELEASE(*ppTypeInfo);
784
+
785
+ return hr;
786
+ }
787
+
788
+ static long
789
+ ole_search_event_at(VALUE ary, VALUE ev)
790
+ {
791
+ VALUE event;
792
+ VALUE event_name;
793
+ long i, len;
794
+ long ret = -1;
795
+ len = RARRAY_LEN(ary);
796
+ for(i = 0; i < len; i++) {
797
+ event = rb_ary_entry(ary, i);
798
+ event_name = rb_ary_entry(event, 1);
799
+ if(NIL_P(event_name) && NIL_P(ev)) {
800
+ ret = i;
801
+ break;
802
+ }
803
+ else if (RB_TYPE_P(ev, T_STRING) &&
804
+ RB_TYPE_P(event_name, T_STRING) &&
805
+ rb_str_cmp(ev, event_name) == 0) {
806
+ ret = i;
807
+ break;
808
+ }
809
+ }
810
+ return ret;
811
+ }
812
+
813
+ static VALUE
814
+ ole_search_event(VALUE ary, VALUE ev, BOOL *is_default)
815
+ {
816
+ VALUE event;
817
+ VALUE def_event;
818
+ VALUE event_name;
819
+ int i, len;
820
+ *is_default = FALSE;
821
+ def_event = Qnil;
822
+ len = RARRAY_LEN(ary);
823
+ for(i = 0; i < len; i++) {
824
+ event = rb_ary_entry(ary, i);
825
+ event_name = rb_ary_entry(event, 1);
826
+ if(NIL_P(event_name)) {
827
+ *is_default = TRUE;
828
+ def_event = event;
829
+ }
830
+ else if (rb_str_cmp(ev, event_name) == 0) {
831
+ *is_default = FALSE;
832
+ return event;
833
+ }
834
+ }
835
+ return def_event;
836
+ }
837
+
838
+ static VALUE
839
+ ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler)
840
+ {
841
+ VALUE mid;
842
+
843
+ *is_default_handler = FALSE;
844
+ mid = rb_to_id(rb_sprintf("on%"PRIsVALUE, ev));
845
+ if (rb_respond_to(handler, mid)) {
846
+ return mid;
847
+ }
848
+ mid = rb_intern("method_missing");
849
+ if (rb_respond_to(handler, mid)) {
850
+ *is_default_handler = TRUE;
851
+ return mid;
852
+ }
853
+ return Qnil;
854
+ }
855
+
856
+ static void
857
+ ole_delete_event(VALUE ary, VALUE ev)
858
+ {
859
+ long at = -1;
860
+ at = ole_search_event_at(ary, ev);
861
+ if (at >= 0) {
862
+ rb_ary_delete_at(ary, at);
863
+ }
864
+ }
865
+
866
+
867
+ static void
868
+ oleevent_free(void *ptr)
869
+ {
870
+ struct oleeventdata *poleev = ptr;
871
+ if (poleev->pConnectionPoint) {
872
+ poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie);
873
+ OLE_RELEASE(poleev->pConnectionPoint);
874
+ poleev->pConnectionPoint = NULL;
875
+ }
876
+ OLE_RELEASE(poleev->pDispatch);
877
+ free(poleev);
878
+ }
879
+
880
+ static size_t
881
+ oleevent_size(const void *ptr)
882
+ {
883
+ return ptr ? sizeof(struct oleeventdata) : 0;
884
+ }
885
+
886
+ static VALUE
887
+ fev_s_allocate(VALUE klass)
888
+ {
889
+ VALUE obj;
890
+ struct oleeventdata *poleev;
891
+ obj = TypedData_Make_Struct(klass, struct oleeventdata, &oleevent_datatype, poleev);
892
+ poleev->dwCookie = 0;
893
+ poleev->pConnectionPoint = NULL;
894
+ poleev->event_id = 0;
895
+ poleev->pDispatch = NULL;
896
+ return obj;
897
+ }
898
+
899
+ static VALUE
900
+ ev_advise(int argc, VALUE *argv, VALUE self)
901
+ {
902
+
903
+ VALUE ole, itf;
904
+ struct oledata *pole = NULL;
905
+ char *pitf;
906
+ HRESULT hr;
907
+ IID iid;
908
+ ITypeInfo *pTypeInfo = 0;
909
+ IDispatch *pDispatch;
910
+ IConnectionPointContainer *pContainer;
911
+ IConnectionPoint *pConnectionPoint;
912
+ IEVENTSINKOBJ *pIEV;
913
+ DWORD dwCookie;
914
+ struct oleeventdata *poleev;
915
+ void *p;
916
+
917
+ rb_scan_args(argc, argv, "11", &ole, &itf);
918
+
919
+ if (!rb_obj_is_kind_of(ole, cWIN32OLE)) {
920
+ rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE object");
921
+ }
922
+
923
+ if(!RB_TYPE_P(itf, T_NIL)) {
924
+ pitf = StringValuePtr(itf);
925
+ hr = find_iid(ole, pitf, &iid, &pTypeInfo);
926
+ }
927
+ else {
928
+ hr = find_default_source(ole, &iid, &pTypeInfo);
929
+ }
930
+ if (FAILED(hr)) {
931
+ ole_raise(hr, rb_eRuntimeError, "interface not found");
932
+ }
933
+
934
+ pole = oledata_get_struct(ole);
935
+ pDispatch = pole->pDispatch;
936
+ hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
937
+ &IID_IConnectionPointContainer,
938
+ &p);
939
+ if (FAILED(hr)) {
940
+ OLE_RELEASE(pTypeInfo);
941
+ ole_raise(hr, eWIN32OLEQueryInterfaceError,
942
+ "failed to query IConnectionPointContainer");
943
+ }
944
+ pContainer = p;
945
+
946
+ hr = pContainer->lpVtbl->FindConnectionPoint(pContainer,
947
+ &iid,
948
+ &pConnectionPoint);
949
+ OLE_RELEASE(pContainer);
950
+ if (FAILED(hr)) {
951
+ OLE_RELEASE(pTypeInfo);
952
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to query IConnectionPoint");
953
+ }
954
+ pIEV = EVENTSINK_Constructor();
955
+ pIEV->m_iid = iid;
956
+ hr = pConnectionPoint->lpVtbl->Advise(pConnectionPoint,
957
+ (IUnknown*)pIEV,
958
+ &dwCookie);
959
+ if (FAILED(hr)) {
960
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "Advise Error");
961
+ }
962
+
963
+ TypedData_Get_Struct(self, struct oleeventdata, &oleevent_datatype, poleev);
964
+ pIEV->m_event_id = evs_length();
965
+ pIEV->pTypeInfo = pTypeInfo;
966
+ poleev->dwCookie = dwCookie;
967
+ poleev->pConnectionPoint = pConnectionPoint;
968
+ poleev->event_id = pIEV->m_event_id;
969
+ poleev->pDispatch = pDispatch;
970
+ OLE_ADDREF(pDispatch);
971
+
972
+ return self;
973
+ }
974
+
975
+ /*
976
+ * call-seq:
977
+ * WIN32OLE_EVENT.new(ole, event) #=> WIN32OLE_EVENT object.
978
+ *
979
+ * Returns OLE event object.
980
+ * The first argument specifies WIN32OLE object.
981
+ * The second argument specifies OLE event name.
982
+ * ie = WIN32OLE.new('InternetExplorer.Application')
983
+ * ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
984
+ */
985
+ static VALUE
986
+ fev_initialize(int argc, VALUE *argv, VALUE self)
987
+ {
988
+ ev_advise(argc, argv, self);
989
+ evs_push(self);
990
+ rb_ivar_set(self, id_events, rb_ary_new());
991
+ fev_set_handler(self, Qnil);
992
+ return self;
993
+ }
994
+
995
+ static void
996
+ ole_msg_loop(void)
997
+ {
998
+ MSG msg;
999
+ while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
1000
+ TranslateMessage(&msg);
1001
+ DispatchMessage(&msg);
1002
+ }
1003
+ }
1004
+
1005
+ /*
1006
+ * call-seq:
1007
+ * WIN32OLE_EVENT.message_loop
1008
+ *
1009
+ * Translates and dispatches Windows message.
1010
+ */
1011
+ static VALUE
1012
+ fev_s_msg_loop(VALUE klass)
1013
+ {
1014
+ ole_msg_loop();
1015
+ return Qnil;
1016
+ }
1017
+
1018
+ static void
1019
+ add_event_call_back(VALUE obj, VALUE event, VALUE data)
1020
+ {
1021
+ VALUE events = rb_ivar_get(obj, id_events);
1022
+ if (NIL_P(events) || !RB_TYPE_P(events, T_ARRAY)) {
1023
+ events = rb_ary_new();
1024
+ rb_ivar_set(obj, id_events, events);
1025
+ }
1026
+ ole_delete_event(events, event);
1027
+ rb_ary_push(events, data);
1028
+ }
1029
+
1030
+ static VALUE
1031
+ ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
1032
+ {
1033
+ struct oleeventdata *poleev;
1034
+ VALUE event, args, data;
1035
+ TypedData_Get_Struct(self, struct oleeventdata, &oleevent_datatype, poleev);
1036
+ if (poleev->pConnectionPoint == NULL) {
1037
+ rb_raise(eWIN32OLERuntimeError, "IConnectionPoint not found. You must call advise at first.");
1038
+ }
1039
+ rb_scan_args(argc, argv, "01*", &event, &args);
1040
+ if(!NIL_P(event)) {
1041
+ if(!RB_TYPE_P(event, T_STRING) && !RB_TYPE_P(event, T_SYMBOL)) {
1042
+ rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
1043
+ }
1044
+ if (RB_TYPE_P(event, T_SYMBOL)) {
1045
+ event = rb_sym2str(event);
1046
+ }
1047
+ }
1048
+ data = rb_ary_new3(4, rb_block_proc(), event, args, is_ary_arg);
1049
+ add_event_call_back(self, event, data);
1050
+ return Qnil;
1051
+ }
1052
+
1053
+ /*
1054
+ * call-seq:
1055
+ * WIN32OLE_EVENT#on_event([event]){...}
1056
+ *
1057
+ * Defines the callback event.
1058
+ * If argument is omitted, this method defines the callback of all events.
1059
+ * If you want to modify reference argument in callback, return hash in
1060
+ * callback. If you want to return value to OLE server as result of callback
1061
+ * use `return' or :return.
1062
+ *
1063
+ * ie = WIN32OLE.new('InternetExplorer.Application')
1064
+ * ev = WIN32OLE_EVENT.new(ie)
1065
+ * ev.on_event("NavigateComplete") {|url| puts url}
1066
+ * ev.on_event() {|ev, *args| puts "#{ev} fired"}
1067
+ *
1068
+ * ev.on_event("BeforeNavigate2") {|*args|
1069
+ * ...
1070
+ * # set true to BeforeNavigate reference argument `Cancel'.
1071
+ * # Cancel is 7-th argument of BeforeNavigate,
1072
+ * # so you can use 6 as key of hash instead of 'Cancel'.
1073
+ * # The argument is counted from 0.
1074
+ * # The hash key of 0 means first argument.)
1075
+ * {:Cancel => true} # or {'Cancel' => true} or {6 => true}
1076
+ * }
1077
+ *
1078
+ * ev.on_event(...) {|*args|
1079
+ * {:return => 1, :xxx => yyy}
1080
+ * }
1081
+ */
1082
+ static VALUE
1083
+ fev_on_event(int argc, VALUE *argv, VALUE self)
1084
+ {
1085
+ return ev_on_event(argc, argv, self, Qfalse);
1086
+ }
1087
+
1088
+ /*
1089
+ * call-seq:
1090
+ * WIN32OLE_EVENT#on_event_with_outargs([event]){...}
1091
+ *
1092
+ * Defines the callback of event.
1093
+ * If you want modify argument in callback,
1094
+ * you could use this method instead of WIN32OLE_EVENT#on_event.
1095
+ *
1096
+ * ie = WIN32OLE.new('InternetExplorer.Application')
1097
+ * ev = WIN32OLE_EVENT.new(ie)
1098
+ * ev.on_event_with_outargs('BeforeNavigate2') {|*args|
1099
+ * args.last[6] = true
1100
+ * }
1101
+ */
1102
+ static VALUE
1103
+ fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self)
1104
+ {
1105
+ return ev_on_event(argc, argv, self, Qtrue);
1106
+ }
1107
+
1108
+ /*
1109
+ * call-seq:
1110
+ * WIN32OLE_EVENT#off_event([event])
1111
+ *
1112
+ * removes the callback of event.
1113
+ *
1114
+ * ie = WIN32OLE.new('InternetExplorer.Application')
1115
+ * ev = WIN32OLE_EVENT.new(ie)
1116
+ * ev.on_event('BeforeNavigate2') {|*args|
1117
+ * args.last[6] = true
1118
+ * }
1119
+ * ...
1120
+ * ev.off_event('BeforeNavigate2')
1121
+ * ...
1122
+ */
1123
+ static VALUE
1124
+ fev_off_event(int argc, VALUE *argv, VALUE self)
1125
+ {
1126
+ VALUE event = Qnil;
1127
+ VALUE events;
1128
+
1129
+ rb_scan_args(argc, argv, "01", &event);
1130
+ if(!NIL_P(event)) {
1131
+ if(!RB_TYPE_P(event, T_STRING) && !RB_TYPE_P(event, T_SYMBOL)) {
1132
+ rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
1133
+ }
1134
+ if (RB_TYPE_P(event, T_SYMBOL)) {
1135
+ event = rb_sym2str(event);
1136
+ }
1137
+ }
1138
+ events = rb_ivar_get(self, id_events);
1139
+ if (NIL_P(events)) {
1140
+ return Qnil;
1141
+ }
1142
+ ole_delete_event(events, event);
1143
+ return Qnil;
1144
+ }
1145
+
1146
+ /*
1147
+ * call-seq:
1148
+ * WIN32OLE_EVENT#unadvise -> nil
1149
+ *
1150
+ * disconnects OLE server. If this method called, then the WIN32OLE_EVENT object
1151
+ * does not receive the OLE server event any more.
1152
+ * This method is trial implementation.
1153
+ *
1154
+ * ie = WIN32OLE.new('InternetExplorer.Application')
1155
+ * ev = WIN32OLE_EVENT.new(ie)
1156
+ * ev.on_event() {...}
1157
+ * ...
1158
+ * ev.unadvise
1159
+ *
1160
+ */
1161
+ static VALUE
1162
+ fev_unadvise(VALUE self)
1163
+ {
1164
+ struct oleeventdata *poleev;
1165
+ TypedData_Get_Struct(self, struct oleeventdata, &oleevent_datatype, poleev);
1166
+ if (poleev->pConnectionPoint) {
1167
+ ole_msg_loop();
1168
+ evs_delete(poleev->event_id);
1169
+ poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie);
1170
+ OLE_RELEASE(poleev->pConnectionPoint);
1171
+ poleev->pConnectionPoint = NULL;
1172
+ }
1173
+ OLE_FREE(poleev->pDispatch);
1174
+ return Qnil;
1175
+ }
1176
+
1177
+ static VALUE
1178
+ evs_push(VALUE ev)
1179
+ {
1180
+ return rb_ary_push(ary_ole_event, ev);
1181
+ }
1182
+
1183
+ static VALUE
1184
+ evs_delete(long i)
1185
+ {
1186
+ rb_ary_store(ary_ole_event, i, Qnil);
1187
+ return Qnil;
1188
+ }
1189
+
1190
+ static VALUE
1191
+ evs_entry(long i)
1192
+ {
1193
+ return rb_ary_entry(ary_ole_event, i);
1194
+ }
1195
+
1196
+ static long
1197
+ evs_length(void)
1198
+ {
1199
+ return RARRAY_LEN(ary_ole_event);
1200
+ }
1201
+
1202
+ /*
1203
+ * call-seq:
1204
+ * WIN32OLE_EVENT#handler=
1205
+ *
1206
+ * sets event handler object. If handler object has onXXX
1207
+ * method according to XXX event, then onXXX method is called
1208
+ * when XXX event occurs.
1209
+ *
1210
+ * If handler object has method_missing and there is no
1211
+ * method according to the event, then method_missing
1212
+ * called and 1-st argument is event name.
1213
+ *
1214
+ * If handler object has onXXX method and there is block
1215
+ * defined by WIN32OLE_EVENT#on_event('XXX'){},
1216
+ * then block is executed but handler object method is not called
1217
+ * when XXX event occurs.
1218
+ *
1219
+ * class Handler
1220
+ * def onStatusTextChange(text)
1221
+ * puts "StatusTextChanged"
1222
+ * end
1223
+ * def onPropertyChange(prop)
1224
+ * puts "PropertyChanged"
1225
+ * end
1226
+ * def method_missing(ev, *arg)
1227
+ * puts "other event #{ev}"
1228
+ * end
1229
+ * end
1230
+ *
1231
+ * handler = Handler.new
1232
+ * ie = WIN32OLE.new('InternetExplorer.Application')
1233
+ * ev = WIN32OLE_EVENT.new(ie)
1234
+ * ev.on_event("StatusTextChange") {|*args|
1235
+ * puts "this block executed."
1236
+ * puts "handler.onStatusTextChange method is not called."
1237
+ * }
1238
+ * ev.handler = handler
1239
+ *
1240
+ */
1241
+ static VALUE
1242
+ fev_set_handler(VALUE self, VALUE val)
1243
+ {
1244
+ return rb_ivar_set(self, rb_intern("handler"), val);
1245
+ }
1246
+
1247
+ /*
1248
+ * call-seq:
1249
+ * WIN32OLE_EVENT#handler
1250
+ *
1251
+ * returns handler object.
1252
+ *
1253
+ */
1254
+ static VALUE
1255
+ fev_get_handler(VALUE self)
1256
+ {
1257
+ return rb_ivar_get(self, rb_intern("handler"));
1258
+ }
1259
+
1260
+ void
1261
+ Init_win32ole_event(void)
1262
+ {
1263
+ #undef rb_intern
1264
+ ary_ole_event = rb_ary_new();
1265
+ rb_gc_register_mark_object(ary_ole_event);
1266
+ id_events = rb_intern("events");
1267
+ cWIN32OLE_EVENT = rb_define_class("WIN32OLE_EVENT", rb_cObject);
1268
+ rb_define_singleton_method(cWIN32OLE_EVENT, "message_loop", fev_s_msg_loop, 0);
1269
+ rb_define_alloc_func(cWIN32OLE_EVENT, fev_s_allocate);
1270
+ rb_define_method(cWIN32OLE_EVENT, "initialize", fev_initialize, -1);
1271
+ rb_define_method(cWIN32OLE_EVENT, "on_event", fev_on_event, -1);
1272
+ rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1);
1273
+ rb_define_method(cWIN32OLE_EVENT, "off_event", fev_off_event, -1);
1274
+ rb_define_method(cWIN32OLE_EVENT, "unadvise", fev_unadvise, 0);
1275
+ rb_define_method(cWIN32OLE_EVENT, "handler=", fev_set_handler, 1);
1276
+ rb_define_method(cWIN32OLE_EVENT, "handler", fev_get_handler, 0);
1277
+ }