win32ole 1.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }