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,4140 @@
1
+ /*
2
+ * (c) 1995 Microsoft Corporation. All rights reserved.
3
+ * Developed by ActiveWare Internet Corp., now known as
4
+ * ActiveState Tool Corp., http://www.ActiveState.com
5
+ *
6
+ * Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy
7
+ * <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net>
8
+ *
9
+ * You may distribute under the terms of either the GNU General Public
10
+ * License or the Artistic License, as specified in the README file
11
+ * of the Perl distribution.
12
+ *
13
+ */
14
+
15
+ /*
16
+ modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp>
17
+ */
18
+
19
+ #include "win32ole.h"
20
+
21
+ /*
22
+ * unfortunately IID_IMultiLanguage2 is not included in any libXXX.a
23
+ * in Cygwin(mingw32).
24
+ */
25
+ #if defined(__CYGWIN__) || defined(__MINGW32__)
26
+ #undef IID_IMultiLanguage2
27
+ const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}};
28
+ #endif
29
+
30
+ #define WIN32OLE_VERSION "1.8.8"
31
+
32
+ typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
33
+ (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
34
+
35
+ typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile,
36
+ UINT uCommand, DWORD dwData);
37
+ typedef BOOL (FNENUMSYSEMCODEPAGES) (CODEPAGE_ENUMPROC, DWORD);
38
+ VALUE cWIN32OLE;
39
+
40
+ #if defined(RB_THREAD_SPECIFIC) && (defined(__CYGWIN__))
41
+ static RB_THREAD_SPECIFIC BOOL g_ole_initialized;
42
+ # define g_ole_initialized_init() ((void)0)
43
+ # define g_ole_initialized_set(val) (g_ole_initialized = (val))
44
+ #else
45
+ static volatile DWORD g_ole_initialized_key = TLS_OUT_OF_INDEXES;
46
+ # define g_ole_initialized (TlsGetValue(g_ole_initialized_key)!=0)
47
+ # define g_ole_initialized_init() (g_ole_initialized_key = TlsAlloc())
48
+ # define g_ole_initialized_set(val) TlsSetValue(g_ole_initialized_key, (void*)(val))
49
+ #endif
50
+
51
+ static BOOL g_uninitialize_hooked = FALSE;
52
+ static BOOL g_cp_installed = FALSE;
53
+ static BOOL g_lcid_installed = FALSE;
54
+ static BOOL g_running_nano = FALSE;
55
+ static HINSTANCE ghhctrl = NULL;
56
+ static HINSTANCE gole32 = NULL;
57
+ static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL;
58
+ static VALUE com_hash;
59
+ static VALUE enc2cp_hash;
60
+ static IDispatchVtbl com_vtbl;
61
+ static UINT cWIN32OLE_cp = CP_ACP;
62
+ static rb_encoding *cWIN32OLE_enc;
63
+ static UINT g_cp_to_check = CP_ACP;
64
+ static char g_lcid_to_check[8 + 1];
65
+ static VARTYPE g_nil_to = VT_ERROR;
66
+ static IMessageFilterVtbl message_filter;
67
+ static IMessageFilter imessage_filter = { &message_filter };
68
+ static IMessageFilter* previous_filter;
69
+
70
+ #if defined(HAVE_TYPE_IMULTILANGUAGE2)
71
+ static IMultiLanguage2 *pIMultiLanguage = NULL;
72
+ #elif defined(HAVE_TYPE_IMULTILANGUAGE)
73
+ static IMultiLanguage *pIMultiLanguage = NULL;
74
+ #else
75
+ #define pIMultiLanguage NULL /* dummy */
76
+ #endif
77
+
78
+ struct oleparam {
79
+ DISPPARAMS dp;
80
+ OLECHAR** pNamedArgs;
81
+ };
82
+
83
+ static HRESULT ( STDMETHODCALLTYPE QueryInterface )(IDispatch __RPC_FAR *, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
84
+ static ULONG ( STDMETHODCALLTYPE AddRef )(IDispatch __RPC_FAR * This);
85
+ static ULONG ( STDMETHODCALLTYPE Release )(IDispatch __RPC_FAR * This);
86
+ static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(IDispatch __RPC_FAR * This, UINT __RPC_FAR *pctinfo);
87
+ static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(IDispatch __RPC_FAR * This, UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo);
88
+ static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(IDispatch __RPC_FAR * This, REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId);
89
+ static HRESULT ( STDMETHODCALLTYPE Invoke )( IDispatch __RPC_FAR * This, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult, EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr);
90
+ static IDispatch* val2dispatch(VALUE val);
91
+ static double rbtime2vtdate(VALUE tmobj);
92
+ static VALUE vtdate2rbtime(double date);
93
+ static rb_encoding *ole_cp2encoding(UINT cp);
94
+ static UINT ole_encoding2cp(rb_encoding *enc);
95
+ NORETURN(static void failed_load_conv51932(void));
96
+ #ifndef pIMultiLanguage
97
+ static void load_conv_function51932(void);
98
+ #endif
99
+ static UINT ole_init_cp(void);
100
+ static void ole_freeexceptinfo(EXCEPINFO *pExInfo);
101
+ static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo);
102
+ static void ole_free(void *ptr);
103
+ static size_t ole_size(const void *ptr);
104
+ static LPWSTR ole_mb2wc(char *pm, int len, UINT cp);
105
+ static VALUE ole_ary_m_entry(VALUE val, LONG *pid);
106
+ static VALUE is_all_index_under(LONG *pid, long *pub, long dim);
107
+ static void * get_ptr_of_variant(VARIANT *pvar);
108
+ static void ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt);
109
+ static long dimension(VALUE val);
110
+ static long ary_len_of_dim(VALUE ary, long dim);
111
+ static VALUE ole_set_member(VALUE self, IDispatch *dispatch);
112
+ static VALUE fole_s_allocate(VALUE klass);
113
+ static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv);
114
+ static VALUE ary_new_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim);
115
+ static void ary_store_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim, VALUE val);
116
+ static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self);
117
+ static HRESULT clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid);
118
+ static VALUE ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others);
119
+ static VALUE ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self);
120
+ static VALUE fole_s_connect(int argc, VALUE *argv, VALUE self);
121
+ static VALUE fole_s_const_load(int argc, VALUE *argv, VALUE self);
122
+ static ULONG reference_count(struct oledata * pole);
123
+ static VALUE fole_s_reference_count(VALUE self, VALUE obj);
124
+ static VALUE fole_s_free(VALUE self, VALUE obj);
125
+ static HWND ole_show_help(VALUE helpfile, VALUE helpcontext);
126
+ static VALUE fole_s_show_help(int argc, VALUE *argv, VALUE self);
127
+ static VALUE fole_s_get_code_page(VALUE self);
128
+ static BOOL CALLBACK installed_code_page_proc(LPTSTR str);
129
+ static BOOL code_page_installed(UINT cp);
130
+ static VALUE fole_s_set_code_page(VALUE self, VALUE vcp);
131
+ static VALUE fole_s_get_locale(VALUE self);
132
+ static BOOL CALLBACK installed_lcid_proc(LPTSTR str);
133
+ static BOOL lcid_installed(LCID lcid);
134
+ static VALUE fole_s_set_locale(VALUE self, VALUE vlcid);
135
+ static VALUE fole_s_create_guid(VALUE self);
136
+ static VALUE fole_s_ole_initialize(VALUE self);
137
+ static VALUE fole_s_ole_uninitialize(VALUE self);
138
+ static VALUE fole_initialize(int argc, VALUE *argv, VALUE self);
139
+ static int hash2named_arg(VALUE key, VALUE val, VALUE pop);
140
+ static VALUE set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end);
141
+ static VALUE ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket);
142
+ static VALUE fole_invoke(int argc, VALUE *argv, VALUE self);
143
+ static VALUE ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind);
144
+ static VALUE fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types);
145
+ static VALUE fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
146
+ static VALUE fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
147
+ static VALUE fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self);
148
+ static VALUE fole_setproperty(int argc, VALUE *argv, VALUE self);
149
+ static VALUE fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self);
150
+ static VALUE ole_propertyput(VALUE self, VALUE property, VALUE value);
151
+ static VALUE fole_free(VALUE self);
152
+ static VALUE ole_each_sub(VALUE pEnumV);
153
+ static VALUE ole_ienum_free(VALUE pEnumV);
154
+ static VALUE fole_each(VALUE self);
155
+ static VALUE fole_missing(int argc, VALUE *argv, VALUE self);
156
+ static HRESULT typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti);
157
+ static VALUE ole_methods(VALUE self, int mask);
158
+ static VALUE fole_methods(VALUE self);
159
+ static VALUE fole_get_methods(VALUE self);
160
+ static VALUE fole_put_methods(VALUE self);
161
+ static VALUE fole_func_methods(VALUE self);
162
+ static VALUE fole_type(VALUE self);
163
+ static VALUE fole_typelib(VALUE self);
164
+ static VALUE fole_query_interface(VALUE self, VALUE str_iid);
165
+ static VALUE fole_respond_to(VALUE self, VALUE method);
166
+ static VALUE ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
167
+ static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
168
+ static VALUE fole_method_help(VALUE self, VALUE cmdname);
169
+ static VALUE fole_activex_initialize(VALUE self);
170
+
171
+ static void com_hash_free(void *ptr);
172
+ static void com_hash_mark(void *ptr);
173
+ static size_t com_hash_size(const void *ptr);
174
+ static void check_nano_server(void);
175
+
176
+ static const rb_data_type_t ole_datatype = {
177
+ "win32ole",
178
+ {NULL, ole_free, ole_size,},
179
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
180
+ };
181
+
182
+ static const rb_data_type_t win32ole_hash_datatype = {
183
+ "win32ole_hash",
184
+ {com_hash_mark, com_hash_free, com_hash_size,},
185
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
186
+ };
187
+
188
+ static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)(
189
+ IMessageFilter __RPC_FAR * This,
190
+ /* [in] */ REFIID riid,
191
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
192
+ {
193
+ if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
194
+ || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0)
195
+ {
196
+ *ppvObject = &message_filter;
197
+ return S_OK;
198
+ }
199
+ return E_NOINTERFACE;
200
+ }
201
+
202
+ static ULONG (STDMETHODCALLTYPE mf_AddRef)(
203
+ IMessageFilter __RPC_FAR * This)
204
+ {
205
+ return 1;
206
+ }
207
+
208
+ static ULONG (STDMETHODCALLTYPE mf_Release)(
209
+ IMessageFilter __RPC_FAR * This)
210
+ {
211
+ return 1;
212
+ }
213
+
214
+ static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)(
215
+ IMessageFilter __RPC_FAR * pThis,
216
+ DWORD dwCallType, //Type of incoming call
217
+ HTASK threadIDCaller, //Task handle calling this task
218
+ DWORD dwTickCount, //Elapsed tick count
219
+ LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure
220
+ )
221
+ {
222
+ #ifdef DEBUG_MESSAGEFILTER
223
+ printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount);
224
+ fflush(stdout);
225
+ #endif
226
+ switch (dwCallType)
227
+ {
228
+ case CALLTYPE_ASYNC:
229
+ case CALLTYPE_TOPLEVEL_CALLPENDING:
230
+ case CALLTYPE_ASYNC_CALLPENDING:
231
+ if (rb_during_gc()) {
232
+ return SERVERCALL_RETRYLATER;
233
+ }
234
+ break;
235
+ default:
236
+ break;
237
+ }
238
+ if (previous_filter) {
239
+ return previous_filter->lpVtbl->HandleInComingCall(previous_filter,
240
+ dwCallType,
241
+ threadIDCaller,
242
+ dwTickCount,
243
+ lpInterfaceInfo);
244
+ }
245
+ return SERVERCALL_ISHANDLED;
246
+ }
247
+
248
+ static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)(
249
+ IMessageFilter* pThis,
250
+ HTASK threadIDCallee, //Server task handle
251
+ DWORD dwTickCount, //Elapsed tick count
252
+ DWORD dwRejectType //Returned rejection message
253
+ )
254
+ {
255
+ if (previous_filter) {
256
+ return previous_filter->lpVtbl->RetryRejectedCall(previous_filter,
257
+ threadIDCallee,
258
+ dwTickCount,
259
+ dwRejectType);
260
+ }
261
+ return 1000;
262
+ }
263
+
264
+ static DWORD (STDMETHODCALLTYPE mf_MessagePending)(
265
+ IMessageFilter* pThis,
266
+ HTASK threadIDCallee, //Called applications task handle
267
+ DWORD dwTickCount, //Elapsed tick count
268
+ DWORD dwPendingType //Call type
269
+ )
270
+ {
271
+ if (rb_during_gc()) {
272
+ return PENDINGMSG_WAITNOPROCESS;
273
+ }
274
+ if (previous_filter) {
275
+ return previous_filter->lpVtbl->MessagePending(previous_filter,
276
+ threadIDCallee,
277
+ dwTickCount,
278
+ dwPendingType);
279
+ }
280
+ return PENDINGMSG_WAITNOPROCESS;
281
+ }
282
+
283
+ typedef struct _Win32OLEIDispatch
284
+ {
285
+ IDispatch dispatch;
286
+ ULONG refcount;
287
+ VALUE obj;
288
+ } Win32OLEIDispatch;
289
+
290
+ static HRESULT ( STDMETHODCALLTYPE QueryInterface )(
291
+ IDispatch __RPC_FAR * This,
292
+ /* [in] */ REFIID riid,
293
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
294
+ {
295
+ if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
296
+ || MEMCMP(riid, &IID_IDispatch, GUID, 1) == 0)
297
+ {
298
+ Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
299
+ p->refcount++;
300
+ *ppvObject = This;
301
+ return S_OK;
302
+ }
303
+ return E_NOINTERFACE;
304
+ }
305
+
306
+ static ULONG ( STDMETHODCALLTYPE AddRef )(
307
+ IDispatch __RPC_FAR * This)
308
+ {
309
+ Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
310
+ return ++(p->refcount);
311
+ }
312
+
313
+ static ULONG ( STDMETHODCALLTYPE Release )(
314
+ IDispatch __RPC_FAR * This)
315
+ {
316
+ Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
317
+ ULONG u = --(p->refcount);
318
+ if (u == 0) {
319
+ st_data_t key = p->obj;
320
+ st_delete(DATA_PTR(com_hash), &key, 0);
321
+ free(p);
322
+ }
323
+ return u;
324
+ }
325
+
326
+ static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(
327
+ IDispatch __RPC_FAR * This,
328
+ /* [out] */ UINT __RPC_FAR *pctinfo)
329
+ {
330
+ return E_NOTIMPL;
331
+ }
332
+
333
+ static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(
334
+ IDispatch __RPC_FAR * This,
335
+ /* [in] */ UINT iTInfo,
336
+ /* [in] */ LCID lcid,
337
+ /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
338
+ {
339
+ return E_NOTIMPL;
340
+ }
341
+
342
+
343
+ static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(
344
+ IDispatch __RPC_FAR * This,
345
+ /* [in] */ REFIID riid,
346
+ /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
347
+ /* [in] */ UINT cNames,
348
+ /* [in] */ LCID lcid,
349
+ /* [size_is][out] */ DISPID __RPC_FAR *rgDispId)
350
+ {
351
+ /*
352
+ Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
353
+ */
354
+ char* psz = ole_wc2mb(*rgszNames); // support only one method
355
+ ID nameid = rb_check_id_cstr(psz, (long)strlen(psz), cWIN32OLE_enc);
356
+ free(psz);
357
+ if ((ID)(DISPID)nameid != nameid) return E_NOINTERFACE;
358
+ *rgDispId = (DISPID)nameid;
359
+ return S_OK;
360
+ }
361
+
362
+ static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )(
363
+ IDispatch __RPC_FAR * This,
364
+ /* [in] */ DISPID dispIdMember,
365
+ /* [in] */ REFIID riid,
366
+ /* [in] */ LCID lcid,
367
+ /* [in] */ WORD wFlags,
368
+ /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
369
+ /* [out] */ VARIANT __RPC_FAR *pVarResult,
370
+ /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
371
+ /* [out] */ UINT __RPC_FAR *puArgErr)
372
+ {
373
+ VALUE v;
374
+ int i;
375
+ int args = pDispParams->cArgs;
376
+ Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
377
+ VALUE* parg = ALLOCA_N(VALUE, args);
378
+ ID mid = (ID)dispIdMember;
379
+ for (i = 0; i < args; i++) {
380
+ *(parg + i) = ole_variant2val(&pDispParams->rgvarg[args - i - 1]);
381
+ }
382
+ if (dispIdMember == DISPID_VALUE) {
383
+ if (wFlags == DISPATCH_METHOD) {
384
+ mid = rb_intern("call");
385
+ } else if (wFlags & DISPATCH_PROPERTYGET) {
386
+ mid = rb_intern("value");
387
+ }
388
+ }
389
+ v = rb_funcallv(p->obj, mid, args, parg);
390
+ ole_val2variant(v, pVarResult);
391
+ return S_OK;
392
+ }
393
+
394
+ BOOL
395
+ ole_initialized(void)
396
+ {
397
+ return g_ole_initialized;
398
+ }
399
+
400
+ static IDispatch*
401
+ val2dispatch(VALUE val)
402
+ {
403
+ struct st_table *tbl = DATA_PTR(com_hash);
404
+ Win32OLEIDispatch* pdisp;
405
+ st_data_t data;
406
+ if (st_lookup(tbl, val, &data)) {
407
+ pdisp = (Win32OLEIDispatch *)(data & ~FIXNUM_FLAG);
408
+ pdisp->refcount++;
409
+ }
410
+ else {
411
+ pdisp = ALLOC(Win32OLEIDispatch);
412
+ pdisp->dispatch.lpVtbl = &com_vtbl;
413
+ pdisp->refcount = 1;
414
+ pdisp->obj = val;
415
+ st_insert(tbl, val, (VALUE)pdisp | FIXNUM_FLAG);
416
+ }
417
+ return &pdisp->dispatch;
418
+ }
419
+
420
+ static double
421
+ rbtime2vtdate(VALUE tmobj)
422
+ {
423
+ SYSTEMTIME st;
424
+ double t;
425
+ double nsec;
426
+
427
+ st.wYear = RB_FIX2INT(rb_funcall(tmobj, rb_intern("year"), 0));
428
+ st.wMonth = RB_FIX2INT(rb_funcall(tmobj, rb_intern("month"), 0));
429
+ st.wDay = RB_FIX2INT(rb_funcall(tmobj, rb_intern("mday"), 0));
430
+ st.wHour = RB_FIX2INT(rb_funcall(tmobj, rb_intern("hour"), 0));
431
+ st.wMinute = RB_FIX2INT(rb_funcall(tmobj, rb_intern("min"), 0));
432
+ st.wSecond = RB_FIX2INT(rb_funcall(tmobj, rb_intern("sec"), 0));
433
+ st.wMilliseconds = 0;
434
+ SystemTimeToVariantTime(&st, &t);
435
+
436
+ /*
437
+ * Unfortunately SystemTimeToVariantTime function always ignores the
438
+ * wMilliseconds of SYSTEMTIME struct.
439
+ * So, we need to calculate milliseconds by ourselves.
440
+ */
441
+ nsec = RB_FIX2INT(rb_funcall(tmobj, rb_intern("nsec"), 0));
442
+ nsec /= 1000000.0;
443
+ nsec /= (24.0 * 3600.0);
444
+ nsec /= 1000;
445
+ return t + nsec;
446
+ }
447
+
448
+ static VALUE
449
+ vtdate2rbtime(double date)
450
+ {
451
+ SYSTEMTIME st;
452
+ VALUE v;
453
+ double msec;
454
+ double sec;
455
+ VariantTimeToSystemTime(date, &st);
456
+ v = rb_funcall(rb_cTime, rb_intern("new"), 6,
457
+ RB_INT2FIX(st.wYear),
458
+ RB_INT2FIX(st.wMonth),
459
+ RB_INT2FIX(st.wDay),
460
+ RB_INT2FIX(st.wHour),
461
+ RB_INT2FIX(st.wMinute),
462
+ RB_INT2FIX(st.wSecond));
463
+ st.wYear = RB_FIX2INT(rb_funcall(v, rb_intern("year"), 0));
464
+ st.wMonth = RB_FIX2INT(rb_funcall(v, rb_intern("month"), 0));
465
+ st.wDay = RB_FIX2INT(rb_funcall(v, rb_intern("mday"), 0));
466
+ st.wHour = RB_FIX2INT(rb_funcall(v, rb_intern("hour"), 0));
467
+ st.wMinute = RB_FIX2INT(rb_funcall(v, rb_intern("min"), 0));
468
+ st.wSecond = RB_FIX2INT(rb_funcall(v, rb_intern("sec"), 0));
469
+ st.wMilliseconds = 0;
470
+ SystemTimeToVariantTime(&st, &sec);
471
+ /*
472
+ * Unfortunately VariantTimeToSystemTime always ignores the
473
+ * wMilliseconds of SYSTEMTIME struct(The wMilliseconds is 0).
474
+ * So, we need to calculate milliseconds by ourselves.
475
+ */
476
+ msec = date - sec;
477
+ msec *= 24 * 60;
478
+ msec -= floor(msec);
479
+ msec *= 60;
480
+ if (msec >= 59) {
481
+ msec -= 60;
482
+ }
483
+ if (msec != 0) {
484
+ return rb_funcall(v, rb_intern("+"), 1, rb_float_new(msec));
485
+ }
486
+ return v;
487
+ }
488
+
489
+ #define ENC_MACHING_CP(enc,encname,cp) if(strcasecmp(rb_enc_name((enc)),(encname)) == 0) return cp
490
+
491
+ static UINT ole_encoding2cp(rb_encoding *enc)
492
+ {
493
+ /*
494
+ * Is there any better solution to convert
495
+ * Ruby encoding to Windows codepage???
496
+ */
497
+ ENC_MACHING_CP(enc, "Big5", 950);
498
+ ENC_MACHING_CP(enc, "CP51932", 51932);
499
+ ENC_MACHING_CP(enc, "CP850", 850);
500
+ ENC_MACHING_CP(enc, "CP852", 852);
501
+ ENC_MACHING_CP(enc, "CP855", 855);
502
+ ENC_MACHING_CP(enc, "CP949", 949);
503
+ ENC_MACHING_CP(enc, "EUC-JP", 20932);
504
+ ENC_MACHING_CP(enc, "EUC-KR", 51949);
505
+ ENC_MACHING_CP(enc, "EUC-TW", 51950);
506
+ ENC_MACHING_CP(enc, "GB18030", 54936);
507
+ ENC_MACHING_CP(enc, "GB2312", 20936);
508
+ ENC_MACHING_CP(enc, "GBK", 936);
509
+ ENC_MACHING_CP(enc, "IBM437", 437);
510
+ ENC_MACHING_CP(enc, "IBM737", 737);
511
+ ENC_MACHING_CP(enc, "IBM775", 775);
512
+ ENC_MACHING_CP(enc, "IBM852", 852);
513
+ ENC_MACHING_CP(enc, "IBM855", 855);
514
+ ENC_MACHING_CP(enc, "IBM857", 857);
515
+ ENC_MACHING_CP(enc, "IBM860", 860);
516
+ ENC_MACHING_CP(enc, "IBM861", 861);
517
+ ENC_MACHING_CP(enc, "IBM862", 862);
518
+ ENC_MACHING_CP(enc, "IBM863", 863);
519
+ ENC_MACHING_CP(enc, "IBM864", 864);
520
+ ENC_MACHING_CP(enc, "IBM865", 865);
521
+ ENC_MACHING_CP(enc, "IBM866", 866);
522
+ ENC_MACHING_CP(enc, "IBM869", 869);
523
+ ENC_MACHING_CP(enc, "ISO-2022-JP", 50220);
524
+ ENC_MACHING_CP(enc, "ISO-8859-1", 28591);
525
+ ENC_MACHING_CP(enc, "ISO-8859-15", 28605);
526
+ ENC_MACHING_CP(enc, "ISO-8859-2", 28592);
527
+ ENC_MACHING_CP(enc, "ISO-8859-3", 28593);
528
+ ENC_MACHING_CP(enc, "ISO-8859-4", 28594);
529
+ ENC_MACHING_CP(enc, "ISO-8859-5", 28595);
530
+ ENC_MACHING_CP(enc, "ISO-8859-6", 28596);
531
+ ENC_MACHING_CP(enc, "ISO-8859-7", 28597);
532
+ ENC_MACHING_CP(enc, "ISO-8859-8", 28598);
533
+ ENC_MACHING_CP(enc, "ISO-8859-9", 28599);
534
+ ENC_MACHING_CP(enc, "KOI8-R", 20866);
535
+ ENC_MACHING_CP(enc, "KOI8-U", 21866);
536
+ ENC_MACHING_CP(enc, "Shift_JIS", 932);
537
+ ENC_MACHING_CP(enc, "UTF-16BE", 1201);
538
+ ENC_MACHING_CP(enc, "UTF-16LE", 1200);
539
+ ENC_MACHING_CP(enc, "UTF-7", 65000);
540
+ ENC_MACHING_CP(enc, "UTF-8", 65001);
541
+ ENC_MACHING_CP(enc, "Windows-1250", 1250);
542
+ ENC_MACHING_CP(enc, "Windows-1251", 1251);
543
+ ENC_MACHING_CP(enc, "Windows-1252", 1252);
544
+ ENC_MACHING_CP(enc, "Windows-1253", 1253);
545
+ ENC_MACHING_CP(enc, "Windows-1254", 1254);
546
+ ENC_MACHING_CP(enc, "Windows-1255", 1255);
547
+ ENC_MACHING_CP(enc, "Windows-1256", 1256);
548
+ ENC_MACHING_CP(enc, "Windows-1257", 1257);
549
+ ENC_MACHING_CP(enc, "Windows-1258", 1258);
550
+ ENC_MACHING_CP(enc, "Windows-31J", 932);
551
+ ENC_MACHING_CP(enc, "Windows-874", 874);
552
+ ENC_MACHING_CP(enc, "eucJP-ms", 20932);
553
+ return CP_ACP;
554
+ }
555
+
556
+ static void
557
+ failed_load_conv51932(void)
558
+ {
559
+ rb_raise(eWIN32OLERuntimeError, "fail to load convert function for CP51932");
560
+ }
561
+
562
+ #ifndef pIMultiLanguage
563
+ static void
564
+ load_conv_function51932(void)
565
+ {
566
+ HRESULT hr = E_NOINTERFACE;
567
+ void *p;
568
+ if (!pIMultiLanguage) {
569
+ #if defined(HAVE_TYPE_IMULTILANGUAGE2)
570
+ hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
571
+ &IID_IMultiLanguage2, &p);
572
+ #elif defined(HAVE_TYPE_IMULTILANGUAGE)
573
+ hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
574
+ &IID_IMultiLanguage, &p);
575
+ #endif
576
+ if (FAILED(hr)) {
577
+ failed_load_conv51932();
578
+ }
579
+ pIMultiLanguage = p;
580
+ }
581
+ }
582
+ #define need_conv_function51932() (load_conv_function51932(), 1)
583
+ #else
584
+ #define load_conv_function51932() failed_load_conv51932()
585
+ #define need_conv_function51932() (failed_load_conv51932(), 0)
586
+ #endif
587
+
588
+ #define conv_51932(cp) ((cp) == 51932 && need_conv_function51932())
589
+
590
+ static void
591
+ set_ole_codepage(UINT cp)
592
+ {
593
+ if (code_page_installed(cp)) {
594
+ cWIN32OLE_cp = cp;
595
+ } else {
596
+ switch(cp) {
597
+ case CP_ACP:
598
+ case CP_OEMCP:
599
+ case CP_MACCP:
600
+ case CP_THREAD_ACP:
601
+ case CP_SYMBOL:
602
+ case CP_UTF7:
603
+ case CP_UTF8:
604
+ cWIN32OLE_cp = cp;
605
+ break;
606
+ case 51932:
607
+ cWIN32OLE_cp = cp;
608
+ load_conv_function51932();
609
+ break;
610
+ default:
611
+ rb_raise(eWIN32OLERuntimeError, "codepage should be WIN32OLE::CP_ACP, WIN32OLE::CP_OEMCP, WIN32OLE::CP_MACCP, WIN32OLE::CP_THREAD_ACP, WIN32OLE::CP_SYMBOL, WIN32OLE::CP_UTF7, WIN32OLE::CP_UTF8, or installed codepage.");
612
+ break;
613
+ }
614
+ }
615
+ cWIN32OLE_enc = ole_cp2encoding(cWIN32OLE_cp);
616
+ }
617
+
618
+
619
+ static UINT
620
+ ole_init_cp(void)
621
+ {
622
+ UINT cp;
623
+ rb_encoding *encdef;
624
+ encdef = rb_default_internal_encoding();
625
+ if (!encdef) {
626
+ encdef = rb_default_external_encoding();
627
+ }
628
+ cp = ole_encoding2cp(encdef);
629
+ set_ole_codepage(cp);
630
+ return cp;
631
+ }
632
+
633
+ struct myCPINFOEX {
634
+ UINT MaxCharSize;
635
+ BYTE DefaultChar[2];
636
+ BYTE LeadByte[12];
637
+ WCHAR UnicodeDefaultChar;
638
+ UINT CodePage;
639
+ char CodePageName[MAX_PATH];
640
+ };
641
+
642
+ static rb_encoding *
643
+ ole_cp2encoding(UINT cp)
644
+ {
645
+ static BOOL (*pGetCPInfoEx)(UINT, DWORD, struct myCPINFOEX *) = NULL;
646
+ struct myCPINFOEX* buf;
647
+ VALUE enc_name;
648
+ char *enc_cstr;
649
+ int idx;
650
+
651
+ if (!code_page_installed(cp)) {
652
+ switch(cp) {
653
+ case CP_ACP:
654
+ cp = GetACP();
655
+ break;
656
+ case CP_OEMCP:
657
+ cp = GetOEMCP();
658
+ break;
659
+ case CP_MACCP:
660
+ case CP_THREAD_ACP:
661
+ if (!pGetCPInfoEx) {
662
+ pGetCPInfoEx = (BOOL (*)(UINT, DWORD, struct myCPINFOEX *))
663
+ GetProcAddress(GetModuleHandle("kernel32"), "GetCPInfoEx");
664
+ if (!pGetCPInfoEx) {
665
+ pGetCPInfoEx = (void*)-1;
666
+ }
667
+ }
668
+ buf = ALLOCA_N(struct myCPINFOEX, 1);
669
+ ZeroMemory(buf, sizeof(struct myCPINFOEX));
670
+ if (pGetCPInfoEx == (void*)-1 || !pGetCPInfoEx(cp, 0, buf)) {
671
+ rb_raise(eWIN32OLERuntimeError, "cannot map codepage to encoding.");
672
+ break; /* never reach here */
673
+ }
674
+ cp = buf->CodePage;
675
+ break;
676
+ case CP_SYMBOL:
677
+ case CP_UTF7:
678
+ case CP_UTF8:
679
+ break;
680
+ case 51932:
681
+ load_conv_function51932();
682
+ break;
683
+ default:
684
+ rb_raise(eWIN32OLERuntimeError, "codepage should be WIN32OLE::CP_ACP, WIN32OLE::CP_OEMCP, WIN32OLE::CP_MACCP, WIN32OLE::CP_THREAD_ACP, WIN32OLE::CP_SYMBOL, WIN32OLE::CP_UTF7, WIN32OLE::CP_UTF8, or installed codepage.");
685
+ break;
686
+ }
687
+ }
688
+
689
+ enc_name = rb_sprintf("CP%d", cp);
690
+ idx = rb_enc_find_index(enc_cstr = StringValueCStr(enc_name));
691
+ if (idx < 0)
692
+ idx = rb_define_dummy_encoding(enc_cstr);
693
+ return rb_enc_from_index(idx);
694
+ }
695
+
696
+ #ifndef pIMultiLanguage
697
+ static HRESULT
698
+ ole_ml_wc2mb_conv0(LPWSTR pw, LPSTR pm, UINT *size)
699
+ {
700
+ DWORD dw = 0;
701
+ return pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage,
702
+ &dw, cWIN32OLE_cp, pw, NULL, pm, size);
703
+ }
704
+ #define ole_ml_wc2mb_conv(pw, pm, size, onfailure) do { \
705
+ HRESULT hr = ole_ml_wc2mb_conv0(pw, pm, &size); \
706
+ if (FAILED(hr)) { \
707
+ onfailure; \
708
+ ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp); \
709
+ } \
710
+ } while (0)
711
+ #endif
712
+
713
+ #define ole_wc2mb_conv(pw, pm, size) WideCharToMultiByte(cWIN32OLE_cp, 0, (pw), -1, (pm), (size), NULL, NULL)
714
+
715
+ static char *
716
+ ole_wc2mb_alloc(LPWSTR pw, char *(alloc)(UINT size, void *arg), void *arg)
717
+ {
718
+ LPSTR pm;
719
+ UINT size = 0;
720
+ if (conv_51932(cWIN32OLE_cp)) {
721
+ #ifndef pIMultiLanguage
722
+ ole_ml_wc2mb_conv(pw, NULL, size, {});
723
+ pm = alloc(size, arg);
724
+ if (size) ole_ml_wc2mb_conv(pw, pm, size, xfree(pm));
725
+ pm[size] = '\0';
726
+ return pm;
727
+ #endif
728
+ }
729
+ size = ole_wc2mb_conv(pw, NULL, 0);
730
+ pm = alloc(size, arg);
731
+ if (size) ole_wc2mb_conv(pw, pm, size);
732
+ pm[size] = '\0';
733
+ return pm;
734
+ }
735
+
736
+ static char *
737
+ ole_alloc_str(UINT size, void *arg)
738
+ {
739
+ return ALLOC_N(char, size + 1);
740
+ }
741
+
742
+ char *
743
+ ole_wc2mb(LPWSTR pw)
744
+ {
745
+ return ole_wc2mb_alloc(pw, ole_alloc_str, NULL);
746
+ }
747
+
748
+ static void
749
+ ole_freeexceptinfo(EXCEPINFO *pExInfo)
750
+ {
751
+ SysFreeString(pExInfo->bstrDescription);
752
+ SysFreeString(pExInfo->bstrSource);
753
+ SysFreeString(pExInfo->bstrHelpFile);
754
+ }
755
+
756
+ static VALUE
757
+ ole_excepinfo2msg(EXCEPINFO *pExInfo)
758
+ {
759
+ char error_code[40];
760
+ char *pSource = NULL;
761
+ char *pDescription = NULL;
762
+ VALUE error_msg;
763
+ if(pExInfo->pfnDeferredFillIn != NULL) {
764
+ (*pExInfo->pfnDeferredFillIn)(pExInfo);
765
+ }
766
+ if (pExInfo->bstrSource != NULL) {
767
+ pSource = ole_wc2mb(pExInfo->bstrSource);
768
+ }
769
+ if (pExInfo->bstrDescription != NULL) {
770
+ pDescription = ole_wc2mb(pExInfo->bstrDescription);
771
+ }
772
+ if(pExInfo->wCode == 0) {
773
+ sprintf(error_code, "\n OLE error code:%lX in ", (unsigned long)pExInfo->scode);
774
+ }
775
+ else{
776
+ sprintf(error_code, "\n OLE error code:%u in ", pExInfo->wCode);
777
+ }
778
+ error_msg = rb_str_new2(error_code);
779
+ if(pSource != NULL) {
780
+ rb_str_cat2(error_msg, pSource);
781
+ }
782
+ else {
783
+ rb_str_cat(error_msg, "<Unknown>", 9);
784
+ }
785
+ rb_str_cat2(error_msg, "\n ");
786
+ if(pDescription != NULL) {
787
+ rb_str_cat2(error_msg, pDescription);
788
+ }
789
+ else {
790
+ rb_str_cat2(error_msg, "<No Description>");
791
+ }
792
+ if(pSource) free(pSource);
793
+ if(pDescription) free(pDescription);
794
+ ole_freeexceptinfo(pExInfo);
795
+ return error_msg;
796
+ }
797
+
798
+ void
799
+ ole_uninitialize(void)
800
+ {
801
+ if (!g_ole_initialized) return;
802
+ OleUninitialize();
803
+ g_ole_initialized_set(FALSE);
804
+ }
805
+
806
+ static void
807
+ ole_uninitialize_hook(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass)
808
+ {
809
+ ole_uninitialize();
810
+ }
811
+
812
+ void
813
+ ole_initialize(void)
814
+ {
815
+ HRESULT hr;
816
+
817
+ if(!g_uninitialize_hooked) {
818
+ rb_add_event_hook(ole_uninitialize_hook, RUBY_EVENT_THREAD_END, Qnil);
819
+ g_uninitialize_hooked = TRUE;
820
+ }
821
+
822
+ if(g_ole_initialized == FALSE) {
823
+ if(g_running_nano) {
824
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
825
+ } else {
826
+ hr = OleInitialize(NULL);
827
+ }
828
+ if(FAILED(hr)) {
829
+ ole_raise(hr, rb_eRuntimeError, "fail: OLE initialize");
830
+ }
831
+ g_ole_initialized_set(TRUE);
832
+
833
+ if (g_running_nano == FALSE) {
834
+ hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter);
835
+ if(FAILED(hr)) {
836
+ previous_filter = NULL;
837
+ ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter");
838
+ }
839
+ }
840
+ }
841
+ }
842
+
843
+ static void
844
+ ole_free(void *ptr)
845
+ {
846
+ struct oledata *pole = ptr;
847
+ OLE_FREE(pole->pDispatch);
848
+ free(pole);
849
+ }
850
+
851
+ static size_t ole_size(const void *ptr)
852
+ {
853
+ return ptr ? sizeof(struct oledata) : 0;
854
+ }
855
+
856
+ struct oledata *
857
+ oledata_get_struct(VALUE ole)
858
+ {
859
+ struct oledata *pole;
860
+ TypedData_Get_Struct(ole, struct oledata, &ole_datatype, pole);
861
+ return pole;
862
+ }
863
+
864
+ LPWSTR
865
+ ole_vstr2wc(VALUE vstr)
866
+ {
867
+ rb_encoding *enc;
868
+ int cp;
869
+ LPWSTR pw;
870
+ st_data_t data;
871
+ struct st_table *tbl = DATA_PTR(enc2cp_hash);
872
+
873
+ /* do not type-conversion here to prevent from other arguments
874
+ * changing (if exist) */
875
+ Check_Type(vstr, T_STRING);
876
+ if (RSTRING_LEN(vstr) == 0) {
877
+ return NULL;
878
+ }
879
+
880
+ enc = rb_enc_get(vstr);
881
+
882
+ if (st_lookup(tbl, (VALUE)enc | FIXNUM_FLAG, &data)) {
883
+ cp = RB_FIX2INT((VALUE)data);
884
+ } else {
885
+ cp = ole_encoding2cp(enc);
886
+ if (code_page_installed(cp) ||
887
+ cp == CP_ACP ||
888
+ cp == CP_OEMCP ||
889
+ cp == CP_MACCP ||
890
+ cp == CP_THREAD_ACP ||
891
+ cp == CP_SYMBOL ||
892
+ cp == CP_UTF7 ||
893
+ cp == CP_UTF8 ||
894
+ cp == 51932) {
895
+ st_insert(tbl, (VALUE)enc | FIXNUM_FLAG, RB_INT2FIX(cp));
896
+ } else {
897
+ rb_raise(eWIN32OLERuntimeError, "not installed Windows codepage(%d) according to `%s'", cp, rb_enc_name(enc));
898
+ }
899
+ }
900
+ pw = ole_mb2wc(RSTRING_PTR(vstr), RSTRING_LENINT(vstr), cp);
901
+ RB_GC_GUARD(vstr);
902
+ return pw;
903
+ }
904
+
905
+ static LPWSTR
906
+ ole_mb2wc(char *pm, int len, UINT cp)
907
+ {
908
+ UINT size = 0;
909
+ LPWSTR pw;
910
+
911
+ if (conv_51932(cp)) {
912
+ #ifndef pIMultiLanguage
913
+ DWORD dw = 0;
914
+ UINT n = len;
915
+ HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
916
+ &dw, cp, pm, &n, NULL, &size);
917
+ if (FAILED(hr)) {
918
+ ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
919
+ }
920
+ pw = SysAllocStringLen(NULL, size);
921
+ n = len;
922
+ hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
923
+ &dw, cp, pm, &n, pw, &size);
924
+ if (FAILED(hr)) {
925
+ ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
926
+ }
927
+ return pw;
928
+ #endif
929
+ }
930
+ size = MultiByteToWideChar(cp, 0, pm, len, NULL, 0);
931
+ pw = SysAllocStringLen(NULL, size);
932
+ pw[size-1] = 0;
933
+ MultiByteToWideChar(cp, 0, pm, len, pw, size);
934
+ return pw;
935
+ }
936
+
937
+ static char *
938
+ ole_alloc_vstr(UINT size, void *arg)
939
+ {
940
+ VALUE str = rb_enc_str_new(NULL, size, cWIN32OLE_enc);
941
+ *(VALUE *)arg = str;
942
+ return RSTRING_PTR(str);
943
+ }
944
+
945
+ VALUE
946
+ ole_wc2vstr(LPWSTR pw, BOOL isfree)
947
+ {
948
+ VALUE vstr;
949
+ ole_wc2mb_alloc(pw, ole_alloc_vstr, &vstr);
950
+ rb_str_set_len(vstr, (long)strlen(RSTRING_PTR(vstr)));
951
+ if(isfree)
952
+ SysFreeString(pw);
953
+ return vstr;
954
+ }
955
+
956
+ static VALUE
957
+ ole_ary_m_entry(VALUE val, LONG *pid)
958
+ {
959
+ VALUE obj = Qnil;
960
+ int i = 0;
961
+ obj = val;
962
+ while(RB_TYPE_P(obj, T_ARRAY)) {
963
+ obj = rb_ary_entry(obj, pid[i]);
964
+ i++;
965
+ }
966
+ return obj;
967
+ }
968
+
969
+ static VALUE
970
+ is_all_index_under(LONG *pid, long *pub, long dim)
971
+ {
972
+ long i = 0;
973
+ for (i = 0; i < dim; i++) {
974
+ if (pid[i] > pub[i]) {
975
+ return Qfalse;
976
+ }
977
+ }
978
+ return Qtrue;
979
+ }
980
+
981
+ void
982
+ ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt)
983
+ {
984
+ if (val == Qnil) {
985
+ if (vt == VT_VARIANT) {
986
+ ole_val2variant2(val, var);
987
+ } else {
988
+ V_VT(var) = (vt & ~VT_BYREF);
989
+ if (V_VT(var) == VT_DISPATCH) {
990
+ V_DISPATCH(var) = NULL;
991
+ } else if (V_VT(var) == VT_UNKNOWN) {
992
+ V_UNKNOWN(var) = NULL;
993
+ }
994
+ }
995
+ return;
996
+ }
997
+ #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
998
+ switch(vt & ~VT_BYREF) {
999
+ case VT_I8:
1000
+ V_VT(var) = VT_I8;
1001
+ V_I8(var) = NUM2I8 (val);
1002
+ break;
1003
+ case VT_UI8:
1004
+ V_VT(var) = VT_UI8;
1005
+ V_UI8(var) = NUM2UI8(val);
1006
+ break;
1007
+ default:
1008
+ ole_val2variant2(val, var);
1009
+ break;
1010
+ }
1011
+ #else /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
1012
+ ole_val2variant2(val, var);
1013
+ #endif
1014
+ }
1015
+
1016
+ VOID *
1017
+ val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt)
1018
+ {
1019
+ VOID *p = NULL;
1020
+ HRESULT hr = S_OK;
1021
+ ole_val2variant_ex(val, var, vt);
1022
+ if ((vt & ~VT_BYREF) == VT_VARIANT) {
1023
+ p = var;
1024
+ } else {
1025
+ if ( (vt & ~VT_BYREF) != V_VT(var)) {
1026
+ hr = VariantChangeTypeEx(var, var,
1027
+ cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF));
1028
+ if (FAILED(hr)) {
1029
+ ole_raise(hr, rb_eRuntimeError, "failed to change type");
1030
+ }
1031
+ }
1032
+ p = get_ptr_of_variant(var);
1033
+ }
1034
+ if (p == NULL) {
1035
+ rb_raise(rb_eRuntimeError, "failed to get pointer of variant");
1036
+ }
1037
+ return p;
1038
+ }
1039
+
1040
+ static void *
1041
+ get_ptr_of_variant(VARIANT *pvar)
1042
+ {
1043
+ switch(V_VT(pvar)) {
1044
+ case VT_UI1:
1045
+ return &V_UI1(pvar);
1046
+ break;
1047
+ case VT_I2:
1048
+ return &V_I2(pvar);
1049
+ break;
1050
+ case VT_UI2:
1051
+ return &V_UI2(pvar);
1052
+ break;
1053
+ case VT_I4:
1054
+ return &V_I4(pvar);
1055
+ break;
1056
+ case VT_UI4:
1057
+ return &V_UI4(pvar);
1058
+ break;
1059
+ case VT_R4:
1060
+ return &V_R4(pvar);
1061
+ break;
1062
+ case VT_R8:
1063
+ return &V_R8(pvar);
1064
+ break;
1065
+ #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1066
+ case VT_I8:
1067
+ return &V_I8(pvar);
1068
+ break;
1069
+ case VT_UI8:
1070
+ return &V_UI8(pvar);
1071
+ break;
1072
+ #endif
1073
+ case VT_INT:
1074
+ return &V_INT(pvar);
1075
+ break;
1076
+ case VT_UINT:
1077
+ return &V_UINT(pvar);
1078
+ break;
1079
+ case VT_CY:
1080
+ return &V_CY(pvar);
1081
+ break;
1082
+ case VT_DATE:
1083
+ return &V_DATE(pvar);
1084
+ break;
1085
+ case VT_BSTR:
1086
+ return V_BSTR(pvar);
1087
+ break;
1088
+ case VT_DISPATCH:
1089
+ return V_DISPATCH(pvar);
1090
+ break;
1091
+ case VT_ERROR:
1092
+ return &V_ERROR(pvar);
1093
+ break;
1094
+ case VT_BOOL:
1095
+ return &V_BOOL(pvar);
1096
+ break;
1097
+ case VT_UNKNOWN:
1098
+ return V_UNKNOWN(pvar);
1099
+ break;
1100
+ case VT_ARRAY:
1101
+ return &V_ARRAY(pvar);
1102
+ break;
1103
+ default:
1104
+ return NULL;
1105
+ break;
1106
+ }
1107
+ }
1108
+
1109
+ static void
1110
+ ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt)
1111
+ {
1112
+ VALUE val1;
1113
+ HRESULT hr = S_OK;
1114
+ VARIANT var;
1115
+ VOID *p = NULL;
1116
+ long i = n;
1117
+ while(i >= 0) {
1118
+ val1 = ole_ary_m_entry(val, pid);
1119
+ VariantInit(&var);
1120
+ p = val2variant_ptr(val1, &var, vt);
1121
+ if (is_all_index_under(pid, pub, dim) == Qtrue) {
1122
+ if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
1123
+ (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
1124
+ rb_raise(eWIN32OLERuntimeError, "element of array does not have IDispatch or IUnknown Interface");
1125
+ }
1126
+ hr = SafeArrayPutElement(psa, pid, p);
1127
+ }
1128
+ if (FAILED(hr)) {
1129
+ ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement");
1130
+ }
1131
+ pid[i] += 1;
1132
+ if (pid[i] > pub[i]) {
1133
+ pid[i] = 0;
1134
+ i -= 1;
1135
+ } else {
1136
+ i = dim - 1;
1137
+ }
1138
+ }
1139
+ }
1140
+
1141
+ static long
1142
+ dimension(VALUE val) {
1143
+ long dim = 0;
1144
+ long dim1 = 0;
1145
+ long len = 0;
1146
+ long i = 0;
1147
+ if (RB_TYPE_P(val, T_ARRAY)) {
1148
+ len = RARRAY_LEN(val);
1149
+ for (i = 0; i < len; i++) {
1150
+ dim1 = dimension(rb_ary_entry(val, i));
1151
+ if (dim < dim1) {
1152
+ dim = dim1;
1153
+ }
1154
+ }
1155
+ dim += 1;
1156
+ }
1157
+ return dim;
1158
+ }
1159
+
1160
+ static long
1161
+ ary_len_of_dim(VALUE ary, long dim) {
1162
+ long ary_len = 0;
1163
+ long ary_len1 = 0;
1164
+ long len = 0;
1165
+ long i = 0;
1166
+ VALUE val;
1167
+ if (dim == 0) {
1168
+ if (RB_TYPE_P(ary, T_ARRAY)) {
1169
+ ary_len = RARRAY_LEN(ary);
1170
+ }
1171
+ } else {
1172
+ if (RB_TYPE_P(ary, T_ARRAY)) {
1173
+ len = RARRAY_LEN(ary);
1174
+ for (i = 0; i < len; i++) {
1175
+ val = rb_ary_entry(ary, i);
1176
+ ary_len1 = ary_len_of_dim(val, dim-1);
1177
+ if (ary_len < ary_len1) {
1178
+ ary_len = ary_len1;
1179
+ }
1180
+ }
1181
+ }
1182
+ }
1183
+ return ary_len;
1184
+ }
1185
+
1186
+ HRESULT
1187
+ ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt)
1188
+ {
1189
+ long dim = 0;
1190
+ int i = 0;
1191
+ HRESULT hr = S_OK;
1192
+
1193
+ SAFEARRAYBOUND *psab = NULL;
1194
+ SAFEARRAY *psa = NULL;
1195
+ long *pub;
1196
+ LONG *pid;
1197
+
1198
+ Check_Type(val, T_ARRAY);
1199
+
1200
+ dim = dimension(val);
1201
+
1202
+ psab = ALLOC_N(SAFEARRAYBOUND, dim);
1203
+ pub = ALLOC_N(long, dim);
1204
+ pid = ALLOC_N(LONG, dim);
1205
+
1206
+ if(!psab || !pub || !pid) {
1207
+ if(pub) free(pub);
1208
+ if(psab) free(psab);
1209
+ if(pid) free(pid);
1210
+ rb_raise(rb_eRuntimeError, "memory allocation error");
1211
+ }
1212
+
1213
+ for (i = 0; i < dim; i++) {
1214
+ psab[i].cElements = ary_len_of_dim(val, i);
1215
+ psab[i].lLbound = 0;
1216
+ pub[i] = psab[i].cElements - 1;
1217
+ pid[i] = 0;
1218
+ }
1219
+ /* Create and fill VARIANT array */
1220
+ if ((vt & ~VT_BYREF) == VT_ARRAY) {
1221
+ vt = (vt | VT_VARIANT);
1222
+ }
1223
+ psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
1224
+ if (psa == NULL)
1225
+ hr = E_OUTOFMEMORY;
1226
+ else
1227
+ hr = SafeArrayLock(psa);
1228
+ if (SUCCEEDED(hr)) {
1229
+ ole_set_safe_array(dim-1, psa, pid, pub, val, dim, (VARTYPE)(vt & VT_TYPEMASK));
1230
+ hr = SafeArrayUnlock(psa);
1231
+ }
1232
+
1233
+ if(pub) free(pub);
1234
+ if(psab) free(psab);
1235
+ if(pid) free(pid);
1236
+
1237
+ if (SUCCEEDED(hr)) {
1238
+ V_VT(var) = vt;
1239
+ V_ARRAY(var) = psa;
1240
+ }
1241
+ else {
1242
+ if (psa != NULL)
1243
+ SafeArrayDestroy(psa);
1244
+ }
1245
+ return hr;
1246
+ }
1247
+
1248
+ void
1249
+ ole_val2variant(VALUE val, VARIANT *var)
1250
+ {
1251
+ struct oledata *pole = NULL;
1252
+ if(rb_obj_is_kind_of(val, cWIN32OLE)) {
1253
+ pole = oledata_get_struct(val);
1254
+ OLE_ADDREF(pole->pDispatch);
1255
+ V_VT(var) = VT_DISPATCH;
1256
+ V_DISPATCH(var) = pole->pDispatch;
1257
+ return;
1258
+ }
1259
+ if (rb_obj_is_kind_of(val, cWIN32OLE_VARIANT)) {
1260
+ ole_variant2variant(val, var);
1261
+ return;
1262
+ }
1263
+ if (rb_obj_is_kind_of(val, cWIN32OLE_RECORD)) {
1264
+ ole_rec2variant(val, var);
1265
+ return;
1266
+ }
1267
+ if (rb_obj_is_kind_of(val, rb_cTime)) {
1268
+ V_VT(var) = VT_DATE;
1269
+ V_DATE(var) = rbtime2vtdate(val);
1270
+ return;
1271
+ }
1272
+ switch (TYPE(val)) {
1273
+ case T_ARRAY:
1274
+ ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY);
1275
+ break;
1276
+ case T_STRING:
1277
+ V_VT(var) = VT_BSTR;
1278
+ V_BSTR(var) = ole_vstr2wc(val);
1279
+ break;
1280
+ case T_FIXNUM:
1281
+ V_VT(var) = VT_I4;
1282
+ {
1283
+ long v = RB_NUM2LONG(val);
1284
+ V_I4(var) = (LONG)v;
1285
+ #if SIZEOF_LONG > 4
1286
+ if (V_I4(var) != v) {
1287
+ V_I8(var) = v;
1288
+ V_VT(var) = VT_I8;
1289
+ }
1290
+ #endif
1291
+ }
1292
+ break;
1293
+ case T_BIGNUM:
1294
+ V_VT(var) = VT_R8;
1295
+ V_R8(var) = rb_big2dbl(val);
1296
+ break;
1297
+ case T_FLOAT:
1298
+ V_VT(var) = VT_R8;
1299
+ V_R8(var) = NUM2DBL(val);
1300
+ break;
1301
+ case T_TRUE:
1302
+ V_VT(var) = VT_BOOL;
1303
+ V_BOOL(var) = VARIANT_TRUE;
1304
+ break;
1305
+ case T_FALSE:
1306
+ V_VT(var) = VT_BOOL;
1307
+ V_BOOL(var) = VARIANT_FALSE;
1308
+ break;
1309
+ case T_NIL:
1310
+ if (g_nil_to == VT_ERROR) {
1311
+ V_VT(var) = VT_ERROR;
1312
+ V_ERROR(var) = DISP_E_PARAMNOTFOUND;
1313
+ }else {
1314
+ V_VT(var) = VT_EMPTY;
1315
+ }
1316
+ break;
1317
+ default:
1318
+ V_VT(var) = VT_DISPATCH;
1319
+ V_DISPATCH(var) = val2dispatch(val);
1320
+ break;
1321
+ }
1322
+ }
1323
+
1324
+ void
1325
+ ole_val2variant2(VALUE val, VARIANT *var)
1326
+ {
1327
+ g_nil_to = VT_EMPTY;
1328
+ ole_val2variant(val, var);
1329
+ g_nil_to = VT_ERROR;
1330
+ }
1331
+
1332
+ VALUE
1333
+ make_inspect(const char *class_name, VALUE detail)
1334
+ {
1335
+ VALUE str;
1336
+ str = rb_str_new2("#<");
1337
+ rb_str_cat2(str, class_name);
1338
+ rb_str_cat2(str, ":");
1339
+ rb_str_concat(str, detail);
1340
+ rb_str_cat2(str, ">");
1341
+ return str;
1342
+ }
1343
+
1344
+ VALUE
1345
+ default_inspect(VALUE self, const char *class_name)
1346
+ {
1347
+ VALUE detail = rb_funcall(self, rb_intern("to_s"), 0);
1348
+ return make_inspect(class_name, detail);
1349
+ }
1350
+
1351
+ static VALUE
1352
+ ole_set_member(VALUE self, IDispatch *dispatch)
1353
+ {
1354
+ struct oledata *pole = NULL;
1355
+ pole = oledata_get_struct(self);
1356
+ if (pole->pDispatch) {
1357
+ OLE_RELEASE(pole->pDispatch);
1358
+ pole->pDispatch = NULL;
1359
+ }
1360
+ pole->pDispatch = dispatch;
1361
+ return self;
1362
+ }
1363
+
1364
+
1365
+ static VALUE
1366
+ fole_s_allocate(VALUE klass)
1367
+ {
1368
+ struct oledata *pole;
1369
+ VALUE obj;
1370
+ ole_initialize();
1371
+ obj = TypedData_Make_Struct(klass, struct oledata, &ole_datatype, pole);
1372
+ pole->pDispatch = NULL;
1373
+ return obj;
1374
+ }
1375
+
1376
+ static VALUE
1377
+ create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv)
1378
+ {
1379
+ VALUE obj = fole_s_allocate(klass);
1380
+ ole_set_member(obj, pDispatch);
1381
+ return obj;
1382
+ }
1383
+
1384
+ static VALUE
1385
+ ary_new_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim) {
1386
+ long i;
1387
+ VALUE obj = Qnil;
1388
+ VALUE pobj = Qnil;
1389
+ long *ids = ALLOC_N(long, dim);
1390
+ if (!ids) {
1391
+ rb_raise(rb_eRuntimeError, "memory allocation error");
1392
+ }
1393
+ for(i = 0; i < dim; i++) {
1394
+ ids[i] = pid[i] - plb[i];
1395
+ }
1396
+ obj = myary;
1397
+ pobj = myary;
1398
+ for(i = 0; i < dim-1; i++) {
1399
+ obj = rb_ary_entry(pobj, ids[i]);
1400
+ if (obj == Qnil) {
1401
+ rb_ary_store(pobj, ids[i], rb_ary_new());
1402
+ }
1403
+ obj = rb_ary_entry(pobj, ids[i]);
1404
+ pobj = obj;
1405
+ }
1406
+ if (ids) free(ids);
1407
+ return obj;
1408
+ }
1409
+
1410
+ static void
1411
+ ary_store_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim, VALUE val) {
1412
+ long id = pid[dim - 1] - plb[dim - 1];
1413
+ VALUE obj = ary_new_dim(myary, pid, plb, dim);
1414
+ rb_ary_store(obj, id, val);
1415
+ }
1416
+
1417
+ VALUE
1418
+ ole_variant2val(VARIANT *pvar)
1419
+ {
1420
+ VALUE obj = Qnil;
1421
+ VARTYPE vt = V_VT(pvar);
1422
+ HRESULT hr;
1423
+ while ( vt == (VT_BYREF | VT_VARIANT) ) {
1424
+ pvar = V_VARIANTREF(pvar);
1425
+ vt = V_VT(pvar);
1426
+ }
1427
+
1428
+ if(V_ISARRAY(pvar)) {
1429
+ VARTYPE vt_base = vt & VT_TYPEMASK;
1430
+ SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar);
1431
+ UINT i = 0;
1432
+ LONG *pid, *plb, *pub;
1433
+ VARIANT variant;
1434
+ VALUE val;
1435
+ UINT dim = 0;
1436
+ if (!psa) {
1437
+ return obj;
1438
+ }
1439
+ dim = SafeArrayGetDim(psa);
1440
+ pid = ALLOC_N(LONG, dim);
1441
+ plb = ALLOC_N(LONG, dim);
1442
+ pub = ALLOC_N(LONG, dim);
1443
+
1444
+ if(!pid || !plb || !pub) {
1445
+ if(pid) free(pid);
1446
+ if(plb) free(plb);
1447
+ if(pub) free(pub);
1448
+ rb_raise(rb_eRuntimeError, "memory allocation error");
1449
+ }
1450
+
1451
+ for(i = 0; i < dim; ++i) {
1452
+ SafeArrayGetLBound(psa, i+1, &plb[i]);
1453
+ SafeArrayGetLBound(psa, i+1, &pid[i]);
1454
+ SafeArrayGetUBound(psa, i+1, &pub[i]);
1455
+ }
1456
+ hr = SafeArrayLock(psa);
1457
+ if (SUCCEEDED(hr)) {
1458
+ obj = rb_ary_new();
1459
+ i = 0;
1460
+ VariantInit(&variant);
1461
+ V_VT(&variant) = vt_base | VT_BYREF;
1462
+ if (vt_base == VT_RECORD) {
1463
+ hr = SafeArrayGetRecordInfo(psa, &V_RECORDINFO(&variant));
1464
+ if (SUCCEEDED(hr)) {
1465
+ V_VT(&variant) = VT_RECORD;
1466
+ }
1467
+ }
1468
+ while (i < dim) {
1469
+ ary_new_dim(obj, pid, plb, dim);
1470
+ if (vt_base == VT_RECORD)
1471
+ hr = SafeArrayPtrOfIndex(psa, pid, &V_RECORD(&variant));
1472
+ else
1473
+ hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
1474
+ if (SUCCEEDED(hr)) {
1475
+ val = ole_variant2val(&variant);
1476
+ ary_store_dim(obj, pid, plb, dim, val);
1477
+ }
1478
+ for (i = 0; i < dim; ++i) {
1479
+ if (++pid[i] <= pub[i])
1480
+ break;
1481
+ pid[i] = plb[i];
1482
+ }
1483
+ }
1484
+ SafeArrayUnlock(psa);
1485
+ }
1486
+ if(pid) free(pid);
1487
+ if(plb) free(plb);
1488
+ if(pub) free(pub);
1489
+ return obj;
1490
+ }
1491
+ switch(V_VT(pvar) & ~VT_BYREF){
1492
+ case VT_EMPTY:
1493
+ break;
1494
+ case VT_NULL:
1495
+ break;
1496
+ case VT_I1:
1497
+ if(V_ISBYREF(pvar))
1498
+ obj = RB_INT2NUM((long)*V_I1REF(pvar));
1499
+ else
1500
+ obj = RB_INT2NUM((long)V_I1(pvar));
1501
+ break;
1502
+
1503
+ case VT_UI1:
1504
+ if(V_ISBYREF(pvar))
1505
+ obj = RB_INT2NUM((long)*V_UI1REF(pvar));
1506
+ else
1507
+ obj = RB_INT2NUM((long)V_UI1(pvar));
1508
+ break;
1509
+
1510
+ case VT_I2:
1511
+ if(V_ISBYREF(pvar))
1512
+ obj = RB_INT2NUM((long)*V_I2REF(pvar));
1513
+ else
1514
+ obj = RB_INT2NUM((long)V_I2(pvar));
1515
+ break;
1516
+
1517
+ case VT_UI2:
1518
+ if(V_ISBYREF(pvar))
1519
+ obj = RB_INT2NUM((long)*V_UI2REF(pvar));
1520
+ else
1521
+ obj = RB_INT2NUM((long)V_UI2(pvar));
1522
+ break;
1523
+
1524
+ case VT_I4:
1525
+ if(V_ISBYREF(pvar))
1526
+ obj = RB_INT2NUM((long)*V_I4REF(pvar));
1527
+ else
1528
+ obj = RB_INT2NUM((long)V_I4(pvar));
1529
+ break;
1530
+
1531
+ case VT_UI4:
1532
+ if(V_ISBYREF(pvar))
1533
+ obj = RB_INT2NUM((long)*V_UI4REF(pvar));
1534
+ else
1535
+ obj = RB_INT2NUM((long)V_UI4(pvar));
1536
+ break;
1537
+
1538
+ case VT_INT:
1539
+ if(V_ISBYREF(pvar))
1540
+ obj = RB_INT2NUM((long)*V_INTREF(pvar));
1541
+ else
1542
+ obj = RB_INT2NUM((long)V_INT(pvar));
1543
+ break;
1544
+
1545
+ case VT_UINT:
1546
+ if(V_ISBYREF(pvar))
1547
+ obj = RB_INT2NUM((long)*V_UINTREF(pvar));
1548
+ else
1549
+ obj = RB_INT2NUM((long)V_UINT(pvar));
1550
+ break;
1551
+
1552
+ #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1553
+ case VT_I8:
1554
+ if(V_ISBYREF(pvar))
1555
+ #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1556
+ #ifdef V_I8REF
1557
+ obj = I8_2_NUM(*V_I8REF(pvar));
1558
+ #endif
1559
+ #else
1560
+ obj = Qnil;
1561
+ #endif
1562
+ else
1563
+ obj = I8_2_NUM(V_I8(pvar));
1564
+ break;
1565
+ case VT_UI8:
1566
+ if(V_ISBYREF(pvar))
1567
+ #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1568
+ #ifdef V_UI8REF
1569
+ obj = UI8_2_NUM(*V_UI8REF(pvar));
1570
+ #endif
1571
+ #else
1572
+ obj = Qnil;
1573
+ #endif
1574
+ else
1575
+ obj = UI8_2_NUM(V_UI8(pvar));
1576
+ break;
1577
+ #endif /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
1578
+
1579
+ case VT_R4:
1580
+ if(V_ISBYREF(pvar))
1581
+ obj = rb_float_new(*V_R4REF(pvar));
1582
+ else
1583
+ obj = rb_float_new(V_R4(pvar));
1584
+ break;
1585
+
1586
+ case VT_R8:
1587
+ if(V_ISBYREF(pvar))
1588
+ obj = rb_float_new(*V_R8REF(pvar));
1589
+ else
1590
+ obj = rb_float_new(V_R8(pvar));
1591
+ break;
1592
+
1593
+ case VT_BSTR:
1594
+ {
1595
+ BSTR bstr;
1596
+ if(V_ISBYREF(pvar))
1597
+ bstr = *V_BSTRREF(pvar);
1598
+ else
1599
+ bstr = V_BSTR(pvar);
1600
+ obj = (SysStringLen(bstr) == 0)
1601
+ ? rb_str_new2("")
1602
+ : ole_wc2vstr(bstr, FALSE);
1603
+ break;
1604
+ }
1605
+
1606
+ case VT_ERROR:
1607
+ if(V_ISBYREF(pvar))
1608
+ obj = RB_INT2NUM(*V_ERRORREF(pvar));
1609
+ else
1610
+ obj = RB_INT2NUM(V_ERROR(pvar));
1611
+ break;
1612
+
1613
+ case VT_BOOL:
1614
+ if (V_ISBYREF(pvar))
1615
+ obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse);
1616
+ else
1617
+ obj = (V_BOOL(pvar) ? Qtrue : Qfalse);
1618
+ break;
1619
+
1620
+ case VT_DISPATCH:
1621
+ {
1622
+ IDispatch *pDispatch;
1623
+
1624
+ if (V_ISBYREF(pvar))
1625
+ pDispatch = *V_DISPATCHREF(pvar);
1626
+ else
1627
+ pDispatch = V_DISPATCH(pvar);
1628
+
1629
+ if (pDispatch != NULL ) {
1630
+ OLE_ADDREF(pDispatch);
1631
+ obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
1632
+ }
1633
+ break;
1634
+ }
1635
+
1636
+ case VT_UNKNOWN:
1637
+ {
1638
+ /* get IDispatch interface from IUnknown interface */
1639
+ IUnknown *punk;
1640
+ IDispatch *pDispatch;
1641
+ void *p;
1642
+ HRESULT hr;
1643
+
1644
+ if (V_ISBYREF(pvar))
1645
+ punk = *V_UNKNOWNREF(pvar);
1646
+ else
1647
+ punk = V_UNKNOWN(pvar);
1648
+
1649
+ if(punk != NULL) {
1650
+ hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch, &p);
1651
+ if(SUCCEEDED(hr)) {
1652
+ pDispatch = p;
1653
+ obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
1654
+ }
1655
+ }
1656
+ break;
1657
+ }
1658
+
1659
+ case VT_DATE:
1660
+ {
1661
+ DATE date;
1662
+ if(V_ISBYREF(pvar))
1663
+ date = *V_DATEREF(pvar);
1664
+ else
1665
+ date = V_DATE(pvar);
1666
+
1667
+ obj = vtdate2rbtime(date);
1668
+ break;
1669
+ }
1670
+
1671
+ case VT_RECORD:
1672
+ {
1673
+ IRecordInfo *pri = V_RECORDINFO(pvar);
1674
+ void *prec = V_RECORD(pvar);
1675
+ obj = create_win32ole_record(pri, prec);
1676
+ break;
1677
+ }
1678
+
1679
+ case VT_CY:
1680
+ default:
1681
+ {
1682
+ HRESULT hr;
1683
+ VARIANT variant;
1684
+ VariantInit(&variant);
1685
+ hr = VariantChangeTypeEx(&variant, pvar,
1686
+ cWIN32OLE_lcid, 0, VT_BSTR);
1687
+ if (SUCCEEDED(hr) && V_VT(&variant) == VT_BSTR) {
1688
+ obj = ole_wc2vstr(V_BSTR(&variant), FALSE);
1689
+ }
1690
+ VariantClear(&variant);
1691
+ break;
1692
+ }
1693
+ }
1694
+ return obj;
1695
+ }
1696
+
1697
+ LONG
1698
+ reg_open_key(HKEY hkey, const char *name, HKEY *phkey)
1699
+ {
1700
+ return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey);
1701
+ }
1702
+
1703
+ LONG
1704
+ reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey)
1705
+ {
1706
+ return reg_open_key(hkey, StringValuePtr(key), phkey);
1707
+ }
1708
+
1709
+ VALUE
1710
+ reg_enum_key(HKEY hkey, DWORD i)
1711
+ {
1712
+ char buf[BUFSIZ + 1];
1713
+ DWORD size_buf = sizeof(buf);
1714
+ FILETIME ft;
1715
+ LONG err = RegEnumKeyEx(hkey, i, buf, &size_buf,
1716
+ NULL, NULL, NULL, &ft);
1717
+ if(err == ERROR_SUCCESS) {
1718
+ buf[BUFSIZ] = '\0';
1719
+ return rb_str_new2(buf);
1720
+ }
1721
+ return Qnil;
1722
+ }
1723
+
1724
+ VALUE
1725
+ reg_get_val(HKEY hkey, const char *subkey)
1726
+ {
1727
+ char *pbuf;
1728
+ DWORD dwtype = 0;
1729
+ DWORD size = 0;
1730
+ VALUE val = Qnil;
1731
+ LONG err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, NULL, &size);
1732
+
1733
+ if (err == ERROR_SUCCESS) {
1734
+ pbuf = ALLOC_N(char, size + 1);
1735
+ err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, (BYTE *)pbuf, &size);
1736
+ if (err == ERROR_SUCCESS) {
1737
+ pbuf[size] = '\0';
1738
+ if (dwtype == REG_EXPAND_SZ) {
1739
+ char* pbuf2 = (char *)pbuf;
1740
+ DWORD len = ExpandEnvironmentStrings(pbuf2, NULL, 0);
1741
+ pbuf = ALLOC_N(char, len + 1);
1742
+ ExpandEnvironmentStrings(pbuf2, pbuf, len + 1);
1743
+ free(pbuf2);
1744
+ }
1745
+ val = rb_str_new2((char *)pbuf);
1746
+ }
1747
+ free(pbuf);
1748
+ }
1749
+ return val;
1750
+ }
1751
+
1752
+ VALUE
1753
+ reg_get_val2(HKEY hkey, const char *subkey)
1754
+ {
1755
+ HKEY hsubkey;
1756
+ LONG err;
1757
+ VALUE val = Qnil;
1758
+ err = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &hsubkey);
1759
+ if (err == ERROR_SUCCESS) {
1760
+ val = reg_get_val(hsubkey, NULL);
1761
+ RegCloseKey(hsubkey);
1762
+ }
1763
+ if (val == Qnil) {
1764
+ val = reg_get_val(hkey, subkey);
1765
+ }
1766
+ return val;
1767
+ }
1768
+
1769
+ static void
1770
+ ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self)
1771
+ {
1772
+ unsigned int count;
1773
+ unsigned int index;
1774
+ int iVar;
1775
+ ITypeInfo *pTypeInfo;
1776
+ TYPEATTR *pTypeAttr;
1777
+ VARDESC *pVarDesc;
1778
+ HRESULT hr;
1779
+ unsigned int len;
1780
+ BSTR bstr;
1781
+ char *pName = NULL;
1782
+ VALUE val;
1783
+ VALUE constant;
1784
+ ID id;
1785
+ constant = rb_hash_new();
1786
+ count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
1787
+ for (index = 0; index < count; index++) {
1788
+ hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, index, &pTypeInfo);
1789
+ if (FAILED(hr))
1790
+ continue;
1791
+ hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
1792
+ if(FAILED(hr)) {
1793
+ OLE_RELEASE(pTypeInfo);
1794
+ continue;
1795
+ }
1796
+ for(iVar = 0; iVar < pTypeAttr->cVars; iVar++) {
1797
+ hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, iVar, &pVarDesc);
1798
+ if(FAILED(hr))
1799
+ continue;
1800
+ if(pVarDesc->varkind == VAR_CONST &&
1801
+ !(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
1802
+ VARFLAG_FRESTRICTED |
1803
+ VARFLAG_FNONBROWSABLE))) {
1804
+ hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
1805
+ 1, &len);
1806
+ if(FAILED(hr) || len == 0 || !bstr)
1807
+ continue;
1808
+ pName = ole_wc2mb(bstr);
1809
+ val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
1810
+ *pName = toupper((int)*pName);
1811
+ id = rb_intern(pName);
1812
+ if (rb_is_const_id(id)) {
1813
+ if(!rb_const_defined_at(klass, id)) {
1814
+ rb_define_const(klass, pName, val);
1815
+ }
1816
+ }
1817
+ else {
1818
+ rb_hash_aset(constant, rb_str_new2(pName), val);
1819
+ }
1820
+ SysFreeString(bstr);
1821
+ if(pName) {
1822
+ free(pName);
1823
+ pName = NULL;
1824
+ }
1825
+ }
1826
+ pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
1827
+ }
1828
+ pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
1829
+ OLE_RELEASE(pTypeInfo);
1830
+ }
1831
+ rb_define_const(klass, "CONSTANTS", constant);
1832
+ }
1833
+
1834
+ static HRESULT
1835
+ clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid)
1836
+ {
1837
+ HKEY hlm;
1838
+ HKEY hpid;
1839
+ VALUE subkey;
1840
+ LONG err;
1841
+ char clsid[100];
1842
+ OLECHAR *pbuf;
1843
+ DWORD len;
1844
+ DWORD dwtype;
1845
+ HRESULT hr = S_OK;
1846
+ err = RegConnectRegistry(StringValuePtr(host), HKEY_LOCAL_MACHINE, &hlm);
1847
+ if (err != ERROR_SUCCESS)
1848
+ return HRESULT_FROM_WIN32(err);
1849
+ subkey = rb_str_new2("SOFTWARE\\Classes\\");
1850
+ rb_str_concat(subkey, com);
1851
+ rb_str_cat2(subkey, "\\CLSID");
1852
+ err = RegOpenKeyEx(hlm, StringValuePtr(subkey), 0, KEY_READ, &hpid);
1853
+ if (err != ERROR_SUCCESS)
1854
+ hr = HRESULT_FROM_WIN32(err);
1855
+ else {
1856
+ len = sizeof(clsid);
1857
+ err = RegQueryValueEx(hpid, "", NULL, &dwtype, (BYTE *)clsid, &len);
1858
+ if (err == ERROR_SUCCESS && dwtype == REG_SZ) {
1859
+ pbuf = ole_mb2wc(clsid, -1, cWIN32OLE_cp);
1860
+ hr = CLSIDFromString(pbuf, pclsid);
1861
+ SysFreeString(pbuf);
1862
+ }
1863
+ else {
1864
+ hr = HRESULT_FROM_WIN32(err);
1865
+ }
1866
+ RegCloseKey(hpid);
1867
+ }
1868
+ RegCloseKey(hlm);
1869
+ return hr;
1870
+ }
1871
+
1872
+ static VALUE
1873
+ ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others)
1874
+ {
1875
+ HRESULT hr;
1876
+ CLSID clsid;
1877
+ OLECHAR *pbuf;
1878
+
1879
+ COSERVERINFO serverinfo;
1880
+ MULTI_QI multi_qi;
1881
+ DWORD clsctx = CLSCTX_REMOTE_SERVER;
1882
+
1883
+ if (!gole32)
1884
+ gole32 = LoadLibrary("OLE32");
1885
+ if (!gole32)
1886
+ rb_raise(rb_eRuntimeError, "failed to load OLE32");
1887
+ if (!gCoCreateInstanceEx)
1888
+ gCoCreateInstanceEx = (FNCOCREATEINSTANCEEX*)
1889
+ GetProcAddress(gole32, "CoCreateInstanceEx");
1890
+ if (!gCoCreateInstanceEx)
1891
+ rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment");
1892
+
1893
+ pbuf = ole_vstr2wc(ole);
1894
+ hr = CLSIDFromProgID(pbuf, &clsid);
1895
+ if (FAILED(hr))
1896
+ hr = clsid_from_remote(host, ole, &clsid);
1897
+ if (FAILED(hr))
1898
+ hr = CLSIDFromString(pbuf, &clsid);
1899
+ SysFreeString(pbuf);
1900
+ if (FAILED(hr))
1901
+ ole_raise(hr, eWIN32OLERuntimeError,
1902
+ "unknown OLE server: `%s'",
1903
+ StringValuePtr(ole));
1904
+ memset(&serverinfo, 0, sizeof(COSERVERINFO));
1905
+ serverinfo.pwszName = ole_vstr2wc(host);
1906
+ memset(&multi_qi, 0, sizeof(MULTI_QI));
1907
+ multi_qi.pIID = &IID_IDispatch;
1908
+ hr = gCoCreateInstanceEx(&clsid, NULL, clsctx, &serverinfo, 1, &multi_qi);
1909
+ SysFreeString(serverinfo.pwszName);
1910
+ if (FAILED(hr))
1911
+ ole_raise(hr, eWIN32OLERuntimeError,
1912
+ "failed to create DCOM server `%s' in `%s'",
1913
+ StringValuePtr(ole),
1914
+ StringValuePtr(host));
1915
+
1916
+ ole_set_member(self, (IDispatch*)multi_qi.pItf);
1917
+ return self;
1918
+ }
1919
+
1920
+ static VALUE
1921
+ ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self)
1922
+ {
1923
+ IBindCtx *pBindCtx;
1924
+ IMoniker *pMoniker;
1925
+ IDispatch *pDispatch;
1926
+ void *p;
1927
+ HRESULT hr;
1928
+ OLECHAR *pbuf;
1929
+ ULONG eaten = 0;
1930
+
1931
+ ole_initialize();
1932
+
1933
+ hr = CreateBindCtx(0, &pBindCtx);
1934
+ if(FAILED(hr)) {
1935
+ ole_raise(hr, eWIN32OLERuntimeError,
1936
+ "failed to create bind context");
1937
+ }
1938
+
1939
+ pbuf = ole_vstr2wc(moniker);
1940
+ hr = MkParseDisplayName(pBindCtx, pbuf, &eaten, &pMoniker);
1941
+ SysFreeString(pbuf);
1942
+ if(FAILED(hr)) {
1943
+ OLE_RELEASE(pBindCtx);
1944
+ ole_raise(hr, eWIN32OLERuntimeError,
1945
+ "failed to parse display name of moniker `%s'",
1946
+ StringValuePtr(moniker));
1947
+ }
1948
+ hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL,
1949
+ &IID_IDispatch, &p);
1950
+ pDispatch = p;
1951
+ OLE_RELEASE(pMoniker);
1952
+ OLE_RELEASE(pBindCtx);
1953
+
1954
+ if(FAILED(hr)) {
1955
+ ole_raise(hr, eWIN32OLERuntimeError,
1956
+ "failed to bind moniker `%s'",
1957
+ StringValuePtr(moniker));
1958
+ }
1959
+ return create_win32ole_object(self, pDispatch, argc, argv);
1960
+ }
1961
+
1962
+ /*
1963
+ * call-seq:
1964
+ * WIN32OLE.connect( ole ) --> aWIN32OLE
1965
+ *
1966
+ * Returns running OLE Automation object or WIN32OLE object from moniker.
1967
+ * 1st argument should be OLE program id or class id or moniker.
1968
+ *
1969
+ * WIN32OLE.connect('Excel.Application') # => WIN32OLE object which represents running Excel.
1970
+ */
1971
+ static VALUE
1972
+ fole_s_connect(int argc, VALUE *argv, VALUE self)
1973
+ {
1974
+ VALUE svr_name;
1975
+ VALUE others;
1976
+ HRESULT hr;
1977
+ CLSID clsid;
1978
+ OLECHAR *pBuf;
1979
+ IDispatch *pDispatch;
1980
+ void *p;
1981
+ IUnknown *pUnknown;
1982
+
1983
+ /* initialize to use OLE */
1984
+ ole_initialize();
1985
+
1986
+ rb_scan_args(argc, argv, "1*", &svr_name, &others);
1987
+ StringValue(svr_name);
1988
+
1989
+ /* get CLSID from OLE server name */
1990
+ pBuf = ole_vstr2wc(svr_name);
1991
+ hr = CLSIDFromProgID(pBuf, &clsid);
1992
+ if(FAILED(hr)) {
1993
+ hr = CLSIDFromString(pBuf, &clsid);
1994
+ }
1995
+ SysFreeString(pBuf);
1996
+ if(FAILED(hr)) {
1997
+ return ole_bind_obj(svr_name, argc, argv, self);
1998
+ }
1999
+
2000
+ hr = GetActiveObject(&clsid, 0, &pUnknown);
2001
+ if (FAILED(hr)) {
2002
+ ole_raise(hr, eWIN32OLERuntimeError,
2003
+ "OLE server `%s' not running", StringValuePtr(svr_name));
2004
+ }
2005
+ hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch, &p);
2006
+ pDispatch = p;
2007
+ if(FAILED(hr)) {
2008
+ OLE_RELEASE(pUnknown);
2009
+ ole_raise(hr, eWIN32OLERuntimeError,
2010
+ "failed to create WIN32OLE server `%s'",
2011
+ StringValuePtr(svr_name));
2012
+ }
2013
+
2014
+ OLE_RELEASE(pUnknown);
2015
+
2016
+ return create_win32ole_object(self, pDispatch, argc, argv);
2017
+ }
2018
+
2019
+ /*
2020
+ * call-seq:
2021
+ * WIN32OLE.const_load( ole, mod = WIN32OLE)
2022
+ *
2023
+ * Defines the constants of OLE Automation server as mod's constants.
2024
+ * The first argument is WIN32OLE object or type library name.
2025
+ * If 2nd argument is omitted, the default is WIN32OLE.
2026
+ * The first letter of Ruby's constant variable name is upper case,
2027
+ * so constant variable name of WIN32OLE object is capitalized.
2028
+ * For example, the 'xlTop' constant of Excel is changed to 'XlTop'
2029
+ * in WIN32OLE.
2030
+ * If the first letter of constant variable is not [A-Z], then
2031
+ * the constant is defined as CONSTANTS hash element.
2032
+ *
2033
+ * module EXCEL_CONST
2034
+ * end
2035
+ * excel = WIN32OLE.new('Excel.Application')
2036
+ * WIN32OLE.const_load(excel, EXCEL_CONST)
2037
+ * puts EXCEL_CONST::XlTop # => -4160
2038
+ * puts EXCEL_CONST::CONSTANTS['_xlDialogChartSourceData'] # => 541
2039
+ *
2040
+ * WIN32OLE.const_load(excel)
2041
+ * puts WIN32OLE::XlTop # => -4160
2042
+ *
2043
+ * module MSO
2044
+ * end
2045
+ * WIN32OLE.const_load('Microsoft Office 9.0 Object Library', MSO)
2046
+ * puts MSO::MsoLineSingle # => 1
2047
+ */
2048
+ static VALUE
2049
+ fole_s_const_load(int argc, VALUE *argv, VALUE self)
2050
+ {
2051
+ VALUE ole;
2052
+ VALUE klass;
2053
+ struct oledata *pole = NULL;
2054
+ ITypeInfo *pTypeInfo;
2055
+ ITypeLib *pTypeLib;
2056
+ unsigned int index;
2057
+ HRESULT hr;
2058
+ OLECHAR *pBuf;
2059
+ VALUE file;
2060
+ LCID lcid = cWIN32OLE_lcid;
2061
+
2062
+ rb_scan_args(argc, argv, "11", &ole, &klass);
2063
+ if (!RB_TYPE_P(klass, T_CLASS) &&
2064
+ !RB_TYPE_P(klass, T_MODULE) &&
2065
+ !RB_TYPE_P(klass, T_NIL)) {
2066
+ rb_raise(rb_eTypeError, "2nd parameter must be Class or Module");
2067
+ }
2068
+ if (rb_obj_is_kind_of(ole, cWIN32OLE)) {
2069
+ pole = oledata_get_struct(ole);
2070
+ hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
2071
+ 0, lcid, &pTypeInfo);
2072
+ if(FAILED(hr)) {
2073
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
2074
+ }
2075
+ hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
2076
+ if(FAILED(hr)) {
2077
+ OLE_RELEASE(pTypeInfo);
2078
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetContainingTypeLib");
2079
+ }
2080
+ OLE_RELEASE(pTypeInfo);
2081
+ if(!RB_TYPE_P(klass, T_NIL)) {
2082
+ ole_const_load(pTypeLib, klass, self);
2083
+ }
2084
+ else {
2085
+ ole_const_load(pTypeLib, cWIN32OLE, self);
2086
+ }
2087
+ OLE_RELEASE(pTypeLib);
2088
+ }
2089
+ else if(RB_TYPE_P(ole, T_STRING)) {
2090
+ file = typelib_file(ole);
2091
+ if (file == Qnil) {
2092
+ file = ole;
2093
+ }
2094
+ pBuf = ole_vstr2wc(file);
2095
+ hr = LoadTypeLibEx(pBuf, REGKIND_NONE, &pTypeLib);
2096
+ SysFreeString(pBuf);
2097
+ if (FAILED(hr))
2098
+ ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx");
2099
+ if(!RB_TYPE_P(klass, T_NIL)) {
2100
+ ole_const_load(pTypeLib, klass, self);
2101
+ }
2102
+ else {
2103
+ ole_const_load(pTypeLib, cWIN32OLE, self);
2104
+ }
2105
+ OLE_RELEASE(pTypeLib);
2106
+ }
2107
+ else {
2108
+ rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE instance");
2109
+ }
2110
+ return Qnil;
2111
+ }
2112
+
2113
+ static ULONG
2114
+ reference_count(struct oledata * pole)
2115
+ {
2116
+ ULONG n = 0;
2117
+ if(pole->pDispatch) {
2118
+ OLE_ADDREF(pole->pDispatch);
2119
+ n = OLE_RELEASE(pole->pDispatch);
2120
+ }
2121
+ return n;
2122
+ }
2123
+
2124
+ /*
2125
+ * call-seq:
2126
+ * WIN32OLE.ole_reference_count(aWIN32OLE) --> number
2127
+ *
2128
+ * Returns reference counter of Dispatch interface of WIN32OLE object.
2129
+ * You should not use this method because this method
2130
+ * exists only for debugging WIN32OLE.
2131
+ */
2132
+ static VALUE
2133
+ fole_s_reference_count(VALUE self, VALUE obj)
2134
+ {
2135
+ struct oledata * pole = NULL;
2136
+ pole = oledata_get_struct(obj);
2137
+ return RB_INT2NUM(reference_count(pole));
2138
+ }
2139
+
2140
+ /*
2141
+ * call-seq:
2142
+ * WIN32OLE.ole_free(aWIN32OLE) --> number
2143
+ *
2144
+ * Invokes Release method of Dispatch interface of WIN32OLE object.
2145
+ * You should not use this method because this method
2146
+ * exists only for debugging WIN32OLE.
2147
+ * The return value is reference counter of OLE object.
2148
+ */
2149
+ static VALUE
2150
+ fole_s_free(VALUE self, VALUE obj)
2151
+ {
2152
+ ULONG n = 0;
2153
+ struct oledata * pole = NULL;
2154
+ pole = oledata_get_struct(obj);
2155
+ if(pole->pDispatch) {
2156
+ if (reference_count(pole) > 0) {
2157
+ n = OLE_RELEASE(pole->pDispatch);
2158
+ }
2159
+ }
2160
+ return RB_INT2NUM(n);
2161
+ }
2162
+
2163
+ static HWND
2164
+ ole_show_help(VALUE helpfile, VALUE helpcontext)
2165
+ {
2166
+ FNHTMLHELP *pfnHtmlHelp;
2167
+ HWND hwnd = 0;
2168
+
2169
+ if(!ghhctrl)
2170
+ ghhctrl = LoadLibrary("HHCTRL.OCX");
2171
+ if (!ghhctrl)
2172
+ return hwnd;
2173
+ pfnHtmlHelp = (FNHTMLHELP*)GetProcAddress(ghhctrl, "HtmlHelpA");
2174
+ if (!pfnHtmlHelp)
2175
+ return hwnd;
2176
+ hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
2177
+ 0x0f, RB_NUM2INT(helpcontext));
2178
+ if (hwnd == 0)
2179
+ hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
2180
+ 0, RB_NUM2INT(helpcontext));
2181
+ return hwnd;
2182
+ }
2183
+
2184
+ /*
2185
+ * call-seq:
2186
+ * WIN32OLE.ole_show_help(obj [,helpcontext])
2187
+ *
2188
+ * Displays helpfile. The 1st argument specifies WIN32OLE_TYPE
2189
+ * object or WIN32OLE_METHOD object or helpfile.
2190
+ *
2191
+ * excel = WIN32OLE.new('Excel.Application')
2192
+ * typeobj = excel.ole_type
2193
+ * WIN32OLE.ole_show_help(typeobj)
2194
+ */
2195
+ static VALUE
2196
+ fole_s_show_help(int argc, VALUE *argv, VALUE self)
2197
+ {
2198
+ VALUE target;
2199
+ VALUE helpcontext;
2200
+ VALUE helpfile;
2201
+ VALUE name;
2202
+ HWND hwnd;
2203
+ rb_scan_args(argc, argv, "11", &target, &helpcontext);
2204
+ if (rb_obj_is_kind_of(target, cWIN32OLE_TYPE) ||
2205
+ rb_obj_is_kind_of(target, cWIN32OLE_METHOD)) {
2206
+ helpfile = rb_funcall(target, rb_intern("helpfile"), 0);
2207
+ if(strlen(StringValuePtr(helpfile)) == 0) {
2208
+ name = rb_ivar_get(target, rb_intern("name"));
2209
+ rb_raise(rb_eRuntimeError, "no helpfile of `%s'",
2210
+ StringValuePtr(name));
2211
+ }
2212
+ helpcontext = rb_funcall(target, rb_intern("helpcontext"), 0);
2213
+ } else {
2214
+ helpfile = target;
2215
+ }
2216
+ if (!RB_TYPE_P(helpfile, T_STRING)) {
2217
+ rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD)");
2218
+ }
2219
+ hwnd = ole_show_help(helpfile, helpcontext);
2220
+ if(hwnd == 0) {
2221
+ rb_raise(rb_eRuntimeError, "failed to open help file `%s'",
2222
+ StringValuePtr(helpfile));
2223
+ }
2224
+ return Qnil;
2225
+ }
2226
+
2227
+ /*
2228
+ * call-seq:
2229
+ * WIN32OLE.codepage
2230
+ *
2231
+ * Returns current codepage.
2232
+ * WIN32OLE.codepage # => WIN32OLE::CP_ACP
2233
+ */
2234
+ static VALUE
2235
+ fole_s_get_code_page(VALUE self)
2236
+ {
2237
+ return RB_INT2FIX(cWIN32OLE_cp);
2238
+ }
2239
+
2240
+ static BOOL CALLBACK
2241
+ installed_code_page_proc(LPTSTR str) {
2242
+ if (strtoul(str, NULL, 10) == g_cp_to_check) {
2243
+ g_cp_installed = TRUE;
2244
+ return FALSE;
2245
+ }
2246
+ return TRUE;
2247
+ }
2248
+
2249
+ static BOOL
2250
+ code_page_installed(UINT cp)
2251
+ {
2252
+ g_cp_installed = FALSE;
2253
+ g_cp_to_check = cp;
2254
+ EnumSystemCodePages(installed_code_page_proc, CP_INSTALLED);
2255
+ return g_cp_installed;
2256
+ }
2257
+
2258
+ /*
2259
+ * call-seq:
2260
+ * WIN32OLE.codepage = CP
2261
+ *
2262
+ * Sets current codepage.
2263
+ * The WIN32OLE.codepage is initialized according to
2264
+ * Encoding.default_internal.
2265
+ * If Encoding.default_internal is nil then WIN32OLE.codepage
2266
+ * is initialized according to Encoding.default_external.
2267
+ *
2268
+ * WIN32OLE.codepage = WIN32OLE::CP_UTF8
2269
+ * WIN32OLE.codepage = 65001
2270
+ */
2271
+ static VALUE
2272
+ fole_s_set_code_page(VALUE self, VALUE vcp)
2273
+ {
2274
+ UINT cp = RB_FIX2INT(vcp);
2275
+ set_ole_codepage(cp);
2276
+ /*
2277
+ * Should this method return old codepage?
2278
+ */
2279
+ return Qnil;
2280
+ }
2281
+
2282
+ /*
2283
+ * call-seq:
2284
+ * WIN32OLE.locale -> locale id.
2285
+ *
2286
+ * Returns current locale id (lcid). The default locale is
2287
+ * WIN32OLE::LOCALE_SYSTEM_DEFAULT.
2288
+ *
2289
+ * lcid = WIN32OLE.locale
2290
+ */
2291
+ static VALUE
2292
+ fole_s_get_locale(VALUE self)
2293
+ {
2294
+ return RB_INT2FIX(cWIN32OLE_lcid);
2295
+ }
2296
+
2297
+ static BOOL
2298
+ CALLBACK installed_lcid_proc(LPTSTR str)
2299
+ {
2300
+ if (strcmp(str, g_lcid_to_check) == 0) {
2301
+ g_lcid_installed = TRUE;
2302
+ return FALSE;
2303
+ }
2304
+ return TRUE;
2305
+ }
2306
+
2307
+ static BOOL
2308
+ lcid_installed(LCID lcid)
2309
+ {
2310
+ g_lcid_installed = FALSE;
2311
+ snprintf(g_lcid_to_check, sizeof(g_lcid_to_check), "%08lx", (unsigned long)lcid);
2312
+ EnumSystemLocales(installed_lcid_proc, LCID_INSTALLED);
2313
+ return g_lcid_installed;
2314
+ }
2315
+
2316
+ /*
2317
+ * call-seq:
2318
+ * WIN32OLE.locale = lcid
2319
+ *
2320
+ * Sets current locale id (lcid).
2321
+ *
2322
+ * WIN32OLE.locale = 1033 # set locale English(U.S)
2323
+ * obj = WIN32OLE_VARIANT.new("$100,000", WIN32OLE::VARIANT::VT_CY)
2324
+ *
2325
+ */
2326
+ static VALUE
2327
+ fole_s_set_locale(VALUE self, VALUE vlcid)
2328
+ {
2329
+ LCID lcid = RB_FIX2INT(vlcid);
2330
+ if (lcid_installed(lcid)) {
2331
+ cWIN32OLE_lcid = lcid;
2332
+ } else {
2333
+ switch (lcid) {
2334
+ case LOCALE_SYSTEM_DEFAULT:
2335
+ case LOCALE_USER_DEFAULT:
2336
+ cWIN32OLE_lcid = lcid;
2337
+ break;
2338
+ default:
2339
+ rb_raise(eWIN32OLERuntimeError, "not installed locale: %u", (unsigned int)lcid);
2340
+ }
2341
+ }
2342
+ return Qnil;
2343
+ }
2344
+
2345
+ /*
2346
+ * call-seq:
2347
+ * WIN32OLE.create_guid
2348
+ *
2349
+ * Creates GUID.
2350
+ * WIN32OLE.create_guid # => {1CB530F1-F6B1-404D-BCE6-1959BF91F4A8}
2351
+ */
2352
+ static VALUE
2353
+ fole_s_create_guid(VALUE self)
2354
+ {
2355
+ GUID guid;
2356
+ HRESULT hr;
2357
+ OLECHAR bstr[80];
2358
+ int len = 0;
2359
+ hr = CoCreateGuid(&guid);
2360
+ if (FAILED(hr)) {
2361
+ ole_raise(hr, eWIN32OLERuntimeError, "failed to create GUID");
2362
+ }
2363
+ len = StringFromGUID2(&guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
2364
+ if (len == 0) {
2365
+ rb_raise(rb_eRuntimeError, "failed to create GUID(buffer over)");
2366
+ }
2367
+ return ole_wc2vstr(bstr, FALSE);
2368
+ }
2369
+
2370
+ /*
2371
+ * WIN32OLE.ole_initialize and WIN32OLE.ole_uninitialize
2372
+ * are used in win32ole.rb to fix the issue bug #2618 (ruby-core:27634).
2373
+ * You must not use these method.
2374
+ */
2375
+
2376
+ /* :nodoc: */
2377
+ static VALUE
2378
+ fole_s_ole_initialize(VALUE self)
2379
+ {
2380
+ ole_initialize();
2381
+ return Qnil;
2382
+ }
2383
+
2384
+ /* :nodoc: */
2385
+ static VALUE
2386
+ fole_s_ole_uninitialize(VALUE self)
2387
+ {
2388
+ ole_uninitialize();
2389
+ return Qnil;
2390
+ }
2391
+
2392
+ /*
2393
+ * Document-class: WIN32OLE
2394
+ *
2395
+ * <code>WIN32OLE</code> objects represent OLE Automation object in Ruby.
2396
+ *
2397
+ * By using WIN32OLE, you can access OLE server like VBScript.
2398
+ *
2399
+ * Here is sample script.
2400
+ *
2401
+ * require 'win32ole'
2402
+ *
2403
+ * excel = WIN32OLE.new('Excel.Application')
2404
+ * excel.visible = true
2405
+ * workbook = excel.Workbooks.Add();
2406
+ * worksheet = workbook.Worksheets(1);
2407
+ * worksheet.Range("A1:D1").value = ["North","South","East","West"];
2408
+ * worksheet.Range("A2:B2").value = [5.2, 10];
2409
+ * worksheet.Range("C2").value = 8;
2410
+ * worksheet.Range("D2").value = 20;
2411
+ *
2412
+ * range = worksheet.Range("A1:D2");
2413
+ * range.select
2414
+ * chart = workbook.Charts.Add;
2415
+ *
2416
+ * workbook.saved = true;
2417
+ *
2418
+ * excel.ActiveWorkbook.Close(0);
2419
+ * excel.Quit();
2420
+ *
2421
+ * Unfortunately, Win32OLE doesn't support the argument passed by
2422
+ * reference directly.
2423
+ * Instead, Win32OLE provides WIN32OLE::ARGV or WIN32OLE_VARIANT object.
2424
+ * If you want to get the result value of argument passed by reference,
2425
+ * you can use WIN32OLE::ARGV or WIN32OLE_VARIANT.
2426
+ *
2427
+ * oleobj.method(arg1, arg2, refargv3)
2428
+ * puts WIN32OLE::ARGV[2] # the value of refargv3 after called oleobj.method
2429
+ *
2430
+ * or
2431
+ *
2432
+ * refargv3 = WIN32OLE_VARIANT.new(XXX,
2433
+ * WIN32OLE::VARIANT::VT_BYREF|WIN32OLE::VARIANT::VT_XXX)
2434
+ * oleobj.method(arg1, arg2, refargv3)
2435
+ * p refargv3.value # the value of refargv3 after called oleobj.method.
2436
+ *
2437
+ */
2438
+
2439
+ /*
2440
+ * call-seq:
2441
+ * WIN32OLE.new(server, [host]) -> WIN32OLE object
2442
+ * WIN32OLE.new(server, license: 'key') -> WIN32OLE object
2443
+ *
2444
+ * Returns a new WIN32OLE object(OLE Automation object).
2445
+ * The first argument server specifies OLE Automation server.
2446
+ * The first argument should be CLSID or PROGID.
2447
+ * If second argument host specified, then returns OLE Automation
2448
+ * object on host.
2449
+ * If :license keyword argument is provided,
2450
+ * IClassFactory2::CreateInstanceLic is used to create instance of
2451
+ * licensed server.
2452
+ *
2453
+ * WIN32OLE.new('Excel.Application') # => Excel OLE Automation WIN32OLE object.
2454
+ * WIN32OLE.new('{00024500-0000-0000-C000-000000000046}') # => Excel OLE Automation WIN32OLE object.
2455
+ */
2456
+ static VALUE
2457
+ fole_initialize(int argc, VALUE *argv, VALUE self)
2458
+ {
2459
+ VALUE svr_name;
2460
+ VALUE host;
2461
+ VALUE others;
2462
+ VALUE opts;
2463
+ HRESULT hr;
2464
+ CLSID clsid;
2465
+ OLECHAR *pBuf;
2466
+ OLECHAR *key_buf;
2467
+ IDispatch *pDispatch;
2468
+ IClassFactory2 * pIClassFactory2;
2469
+ void *p;
2470
+ static ID keyword_ids[1];
2471
+ VALUE kwargs[1];
2472
+
2473
+ rb_call_super(0, 0);
2474
+ rb_scan_args(argc, argv, "11*:", &svr_name, &host, &others, &opts);
2475
+
2476
+ StringValue(svr_name);
2477
+ if (!NIL_P(host)) {
2478
+ StringValue(host);
2479
+ return ole_create_dcom(self, svr_name, host, others);
2480
+ }
2481
+
2482
+ /* get CLSID from OLE server name */
2483
+ pBuf = ole_vstr2wc(svr_name);
2484
+ hr = CLSIDFromProgID(pBuf, &clsid);
2485
+ if(FAILED(hr)) {
2486
+ hr = CLSIDFromString(pBuf, &clsid);
2487
+ }
2488
+ SysFreeString(pBuf);
2489
+ if(FAILED(hr)) {
2490
+ ole_raise(hr, eWIN32OLERuntimeError,
2491
+ "unknown OLE server: `%s'",
2492
+ StringValuePtr(svr_name));
2493
+ }
2494
+
2495
+ if (!keyword_ids[0]) {
2496
+ keyword_ids[0] = rb_intern_const("license");
2497
+ }
2498
+ rb_get_kwargs(opts, keyword_ids, 0, 1, kwargs);
2499
+
2500
+ if (kwargs[0] == Qundef) {
2501
+ /* get IDispatch interface */
2502
+ hr = CoCreateInstance(
2503
+ &clsid,
2504
+ NULL,
2505
+ CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
2506
+ &IID_IDispatch,
2507
+ &p
2508
+ );
2509
+ } else {
2510
+ hr = CoGetClassObject(
2511
+ &clsid,
2512
+ CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
2513
+ NULL,
2514
+ &IID_IClassFactory2,
2515
+ (LPVOID)&pIClassFactory2
2516
+ );
2517
+ if (hr == S_OK) {
2518
+ key_buf = ole_vstr2wc(kwargs[0]);
2519
+ hr = pIClassFactory2->lpVtbl->CreateInstanceLic(pIClassFactory2, NULL, NULL, &IID_IDispatch, key_buf, &p);
2520
+ SysFreeString(key_buf);
2521
+ OLE_RELEASE(pIClassFactory2);
2522
+ }
2523
+ }
2524
+ pDispatch = p;
2525
+ if(FAILED(hr)) {
2526
+ ole_raise(hr, eWIN32OLERuntimeError,
2527
+ "failed to create WIN32OLE object from `%s'",
2528
+ StringValuePtr(svr_name));
2529
+ }
2530
+
2531
+ ole_set_member(self, pDispatch);
2532
+ return self;
2533
+ }
2534
+
2535
+ static int
2536
+ hash2named_arg(VALUE key, VALUE val, VALUE pop)
2537
+ {
2538
+ struct oleparam* pOp = (struct oleparam *)pop;
2539
+ unsigned int index, i;
2540
+ index = pOp->dp.cNamedArgs;
2541
+ /*---------------------------------------------
2542
+ the data-type of key must be String or Symbol
2543
+ -----------------------------------------------*/
2544
+ if(!RB_TYPE_P(key, T_STRING) && !RB_TYPE_P(key, T_SYMBOL)) {
2545
+ /* clear name of dispatch parameters */
2546
+ for(i = 1; i < index + 1; i++) {
2547
+ SysFreeString(pOp->pNamedArgs[i]);
2548
+ }
2549
+ /* clear dispatch parameters */
2550
+ for(i = 0; i < index; i++ ) {
2551
+ VariantClear(&(pOp->dp.rgvarg[i]));
2552
+ }
2553
+ /* raise an exception */
2554
+ rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
2555
+ }
2556
+ if (RB_TYPE_P(key, T_SYMBOL)) {
2557
+ key = rb_sym2str(key);
2558
+ }
2559
+
2560
+ /* pNamedArgs[0] is <method name>, so "index + 1" */
2561
+ pOp->pNamedArgs[index + 1] = ole_vstr2wc(key);
2562
+
2563
+ VariantInit(&(pOp->dp.rgvarg[index]));
2564
+ ole_val2variant(val, &(pOp->dp.rgvarg[index]));
2565
+
2566
+ pOp->dp.cNamedArgs += 1;
2567
+ return ST_CONTINUE;
2568
+ }
2569
+
2570
+ static VALUE
2571
+ set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end)
2572
+ {
2573
+ VALUE argv = rb_const_get(cWIN32OLE, rb_intern("ARGV"));
2574
+
2575
+ Check_Type(argv, T_ARRAY);
2576
+ rb_ary_clear(argv);
2577
+ while (end-- > beg) {
2578
+ rb_ary_push(argv, ole_variant2val(&realargs[end]));
2579
+ if (V_VT(&realargs[end]) != VT_RECORD) {
2580
+ VariantClear(&realargs[end]);
2581
+ }
2582
+ }
2583
+ return argv;
2584
+ }
2585
+
2586
+ static VALUE
2587
+ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket)
2588
+ {
2589
+ LCID lcid = cWIN32OLE_lcid;
2590
+ struct oledata *pole = NULL;
2591
+ HRESULT hr;
2592
+ VALUE cmd;
2593
+ VALUE paramS;
2594
+ VALUE param;
2595
+ VALUE obj;
2596
+ VALUE v;
2597
+
2598
+ BSTR wcmdname;
2599
+
2600
+ DISPID DispID;
2601
+ DISPID* pDispID;
2602
+ EXCEPINFO excepinfo;
2603
+ VARIANT result;
2604
+ VARIANTARG* realargs = NULL;
2605
+ unsigned int argErr = 0;
2606
+ unsigned int i;
2607
+ unsigned int cNamedArgs;
2608
+ int n;
2609
+ struct oleparam op;
2610
+ memset(&excepinfo, 0, sizeof(EXCEPINFO));
2611
+
2612
+ VariantInit(&result);
2613
+
2614
+ op.dp.rgvarg = NULL;
2615
+ op.dp.rgdispidNamedArgs = NULL;
2616
+ op.dp.cNamedArgs = 0;
2617
+ op.dp.cArgs = 0;
2618
+
2619
+ rb_scan_args(argc, argv, "1*", &cmd, &paramS);
2620
+ if(!RB_TYPE_P(cmd, T_STRING) && !RB_TYPE_P(cmd, T_SYMBOL) && !is_bracket) {
2621
+ rb_raise(rb_eTypeError, "method is wrong type (expected String or Symbol)");
2622
+ }
2623
+ if (RB_TYPE_P(cmd, T_SYMBOL)) {
2624
+ cmd = rb_sym2str(cmd);
2625
+ }
2626
+ pole = oledata_get_struct(self);
2627
+ if(!pole->pDispatch) {
2628
+ rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
2629
+ }
2630
+ if (is_bracket) {
2631
+ DispID = DISPID_VALUE;
2632
+ argc += 1;
2633
+ rb_ary_unshift(paramS, cmd);
2634
+ } else {
2635
+ wcmdname = ole_vstr2wc(cmd);
2636
+ hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
2637
+ &wcmdname, 1, lcid, &DispID);
2638
+ SysFreeString(wcmdname);
2639
+ if(FAILED(hr)) {
2640
+ return rb_eNoMethodError;
2641
+ }
2642
+ }
2643
+
2644
+ /* pick up last argument of method */
2645
+ param = rb_ary_entry(paramS, argc-2);
2646
+
2647
+ op.dp.cNamedArgs = 0;
2648
+
2649
+ /* if last arg is hash object */
2650
+ if(RB_TYPE_P(param, T_HASH)) {
2651
+ /*------------------------------------------
2652
+ hash object ==> named dispatch parameters
2653
+ --------------------------------------------*/
2654
+ cNamedArgs = rb_long2int(RHASH_SIZE(param));
2655
+ op.dp.cArgs = cNamedArgs + argc - 2;
2656
+ op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
2657
+ op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
2658
+
2659
+ rb_hash_foreach(param, hash2named_arg, (VALUE)&op);
2660
+
2661
+ pDispID = ALLOCA_N(DISPID, cNamedArgs + 1);
2662
+ op.pNamedArgs[0] = ole_vstr2wc(cmd);
2663
+ hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch,
2664
+ &IID_NULL,
2665
+ op.pNamedArgs,
2666
+ op.dp.cNamedArgs + 1,
2667
+ lcid, pDispID);
2668
+ for(i = 0; i < op.dp.cNamedArgs + 1; i++) {
2669
+ SysFreeString(op.pNamedArgs[i]);
2670
+ op.pNamedArgs[i] = NULL;
2671
+ }
2672
+ if(FAILED(hr)) {
2673
+ /* clear dispatch parameters */
2674
+ for(i = 0; i < op.dp.cArgs; i++ ) {
2675
+ VariantClear(&op.dp.rgvarg[i]);
2676
+ }
2677
+ ole_raise(hr, eWIN32OLERuntimeError,
2678
+ "failed to get named argument info: `%s'",
2679
+ StringValuePtr(cmd));
2680
+ }
2681
+ op.dp.rgdispidNamedArgs = &(pDispID[1]);
2682
+ }
2683
+ else {
2684
+ cNamedArgs = 0;
2685
+ op.dp.cArgs = argc - 1;
2686
+ op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
2687
+ if (op.dp.cArgs > 0) {
2688
+ op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
2689
+ }
2690
+ }
2691
+ /*--------------------------------------
2692
+ non hash args ==> dispatch parameters
2693
+ ----------------------------------------*/
2694
+ if(op.dp.cArgs > cNamedArgs) {
2695
+ realargs = ALLOCA_N(VARIANTARG, op.dp.cArgs-cNamedArgs+1);
2696
+ for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2697
+ n = op.dp.cArgs - i + cNamedArgs - 1;
2698
+ VariantInit(&realargs[n]);
2699
+ VariantInit(&op.dp.rgvarg[n]);
2700
+ param = rb_ary_entry(paramS, i-cNamedArgs);
2701
+ if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
2702
+ ole_variant2variant(param, &op.dp.rgvarg[n]);
2703
+ } else if (rb_obj_is_kind_of(param, cWIN32OLE_RECORD)) {
2704
+ ole_val2variant(param, &realargs[n]);
2705
+ op.dp.rgvarg[n] = realargs[n];
2706
+ V_VT(&op.dp.rgvarg[n]) = VT_RECORD | VT_BYREF;
2707
+ } else {
2708
+ ole_val2variant(param, &realargs[n]);
2709
+ V_VT(&op.dp.rgvarg[n]) = VT_VARIANT | VT_BYREF;
2710
+ V_VARIANTREF(&op.dp.rgvarg[n]) = &realargs[n];
2711
+ }
2712
+ }
2713
+ }
2714
+ /* apparent you need to call propput, you need this */
2715
+ if (wFlags & DISPATCH_PROPERTYPUT) {
2716
+ if (op.dp.cArgs == 0)
2717
+ ole_raise(ResultFromScode(E_INVALIDARG), eWIN32OLERuntimeError, "argument error");
2718
+
2719
+ op.dp.cNamedArgs = 1;
2720
+ op.dp.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
2721
+ op.dp.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
2722
+ }
2723
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2724
+ &IID_NULL, lcid, wFlags, &op.dp,
2725
+ &result, &excepinfo, &argErr);
2726
+
2727
+ if (FAILED(hr)) {
2728
+ /* retry to call args by value */
2729
+ if(op.dp.cArgs >= cNamedArgs) {
2730
+ for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2731
+ n = op.dp.cArgs - i + cNamedArgs - 1;
2732
+ param = rb_ary_entry(paramS, i-cNamedArgs);
2733
+ ole_val2variant(param, &op.dp.rgvarg[n]);
2734
+ }
2735
+ if (hr == DISP_E_EXCEPTION) {
2736
+ ole_freeexceptinfo(&excepinfo);
2737
+ }
2738
+ memset(&excepinfo, 0, sizeof(EXCEPINFO));
2739
+ VariantInit(&result);
2740
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2741
+ &IID_NULL, lcid, wFlags,
2742
+ &op.dp, &result,
2743
+ &excepinfo, &argErr);
2744
+
2745
+ /* mega kludge. if a method in WORD is called and we ask
2746
+ * for a result when one is not returned then
2747
+ * hResult == DISP_E_EXCEPTION. this only happens on
2748
+ * functions whose DISPID > 0x8000 */
2749
+ if ((hr == DISP_E_EXCEPTION || hr == DISP_E_MEMBERNOTFOUND) && DispID > 0x8000) {
2750
+ if (hr == DISP_E_EXCEPTION) {
2751
+ ole_freeexceptinfo(&excepinfo);
2752
+ }
2753
+ memset(&excepinfo, 0, sizeof(EXCEPINFO));
2754
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2755
+ &IID_NULL, lcid, wFlags,
2756
+ &op.dp, NULL,
2757
+ &excepinfo, &argErr);
2758
+
2759
+ }
2760
+ for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2761
+ n = op.dp.cArgs - i + cNamedArgs - 1;
2762
+ if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) {
2763
+ VariantClear(&op.dp.rgvarg[n]);
2764
+ }
2765
+ }
2766
+ }
2767
+
2768
+ if (FAILED(hr)) {
2769
+ /* retry after converting nil to VT_EMPTY */
2770
+ if (op.dp.cArgs > cNamedArgs) {
2771
+ for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2772
+ n = op.dp.cArgs - i + cNamedArgs - 1;
2773
+ param = rb_ary_entry(paramS, i-cNamedArgs);
2774
+ ole_val2variant2(param, &op.dp.rgvarg[n]);
2775
+ }
2776
+ if (hr == DISP_E_EXCEPTION) {
2777
+ ole_freeexceptinfo(&excepinfo);
2778
+ }
2779
+ memset(&excepinfo, 0, sizeof(EXCEPINFO));
2780
+ VariantInit(&result);
2781
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2782
+ &IID_NULL, lcid, wFlags,
2783
+ &op.dp, &result,
2784
+ &excepinfo, &argErr);
2785
+ for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2786
+ n = op.dp.cArgs - i + cNamedArgs - 1;
2787
+ if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) {
2788
+ VariantClear(&op.dp.rgvarg[n]);
2789
+ }
2790
+ }
2791
+ }
2792
+ }
2793
+
2794
+ }
2795
+ /* clear dispatch parameter */
2796
+ if(op.dp.cArgs > cNamedArgs) {
2797
+ for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2798
+ n = op.dp.cArgs - i + cNamedArgs - 1;
2799
+ param = rb_ary_entry(paramS, i-cNamedArgs);
2800
+ if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
2801
+ ole_val2variant(param, &realargs[n]);
2802
+ } else if ( rb_obj_is_kind_of(param, cWIN32OLE_RECORD) &&
2803
+ V_VT(&realargs[n]) == VT_RECORD ) {
2804
+ olerecord_set_ivar(param, V_RECORDINFO(&realargs[n]), V_RECORD(&realargs[n]));
2805
+ }
2806
+ }
2807
+ set_argv(realargs, cNamedArgs, op.dp.cArgs);
2808
+ }
2809
+ else {
2810
+ for(i = 0; i < op.dp.cArgs; i++) {
2811
+ VariantClear(&op.dp.rgvarg[i]);
2812
+ }
2813
+ }
2814
+
2815
+ if (FAILED(hr)) {
2816
+ v = ole_excepinfo2msg(&excepinfo);
2817
+ ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `%s': )%s",
2818
+ StringValuePtr(cmd),
2819
+ StringValuePtr(v));
2820
+ }
2821
+ obj = ole_variant2val(&result);
2822
+ VariantClear(&result);
2823
+ return obj;
2824
+ }
2825
+
2826
+ /*
2827
+ * call-seq:
2828
+ * WIN32OLE#invoke(method, [arg1,...]) => return value of method.
2829
+ *
2830
+ * Runs OLE method.
2831
+ * The first argument specifies the method name of OLE Automation object.
2832
+ * The others specify argument of the <i>method</i>.
2833
+ * If you can not execute <i>method</i> directly, then use this method instead.
2834
+ *
2835
+ * excel = WIN32OLE.new('Excel.Application')
2836
+ * excel.invoke('Quit') # => same as excel.Quit
2837
+ *
2838
+ */
2839
+ static VALUE
2840
+ fole_invoke(int argc, VALUE *argv, VALUE self)
2841
+ {
2842
+ VALUE v = ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
2843
+ if (v == rb_eNoMethodError) {
2844
+ return rb_call_super(argc, argv);
2845
+ }
2846
+ return v;
2847
+ }
2848
+
2849
+ static VALUE
2850
+ ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind)
2851
+ {
2852
+ HRESULT hr;
2853
+ struct oledata *pole = NULL;
2854
+ unsigned int argErr = 0;
2855
+ EXCEPINFO excepinfo;
2856
+ VARIANT result;
2857
+ DISPPARAMS dispParams;
2858
+ VARIANTARG* realargs = NULL;
2859
+ int i, j; VALUE obj = Qnil;
2860
+ VALUE tp, param;
2861
+ VALUE v;
2862
+ VARTYPE vt;
2863
+
2864
+ Check_Type(args, T_ARRAY);
2865
+ Check_Type(types, T_ARRAY);
2866
+
2867
+ memset(&excepinfo, 0, sizeof(EXCEPINFO));
2868
+ memset(&dispParams, 0, sizeof(DISPPARAMS));
2869
+ VariantInit(&result);
2870
+ pole = oledata_get_struct(self);
2871
+
2872
+ dispParams.cArgs = RARRAY_LEN(args);
2873
+ dispParams.rgvarg = ALLOCA_N(VARIANTARG, dispParams.cArgs);
2874
+ realargs = ALLOCA_N(VARIANTARG, dispParams.cArgs);
2875
+ for (i = 0, j = dispParams.cArgs - 1; i < (int)dispParams.cArgs; i++, j--)
2876
+ {
2877
+ VariantInit(&realargs[i]);
2878
+ VariantInit(&dispParams.rgvarg[i]);
2879
+ tp = rb_ary_entry(types, j);
2880
+ vt = (VARTYPE)RB_FIX2INT(tp);
2881
+ V_VT(&dispParams.rgvarg[i]) = vt;
2882
+ param = rb_ary_entry(args, j);
2883
+ if (param == Qnil)
2884
+ {
2885
+
2886
+ V_VT(&dispParams.rgvarg[i]) = V_VT(&realargs[i]) = VT_ERROR;
2887
+ V_ERROR(&dispParams.rgvarg[i]) = V_ERROR(&realargs[i]) = DISP_E_PARAMNOTFOUND;
2888
+ }
2889
+ else
2890
+ {
2891
+ if (vt & VT_ARRAY)
2892
+ {
2893
+ int ent;
2894
+ LPBYTE pb;
2895
+ short* ps;
2896
+ LPLONG pl;
2897
+ VARIANT* pv;
2898
+ CY *py;
2899
+ VARTYPE v;
2900
+ SAFEARRAYBOUND rgsabound[1];
2901
+ Check_Type(param, T_ARRAY);
2902
+ rgsabound[0].lLbound = 0;
2903
+ rgsabound[0].cElements = RARRAY_LEN(param);
2904
+ v = vt & ~(VT_ARRAY | VT_BYREF);
2905
+ V_ARRAY(&realargs[i]) = SafeArrayCreate(v, 1, rgsabound);
2906
+ V_VT(&realargs[i]) = VT_ARRAY | v;
2907
+ SafeArrayLock(V_ARRAY(&realargs[i]));
2908
+ pb = V_ARRAY(&realargs[i])->pvData;
2909
+ ps = V_ARRAY(&realargs[i])->pvData;
2910
+ pl = V_ARRAY(&realargs[i])->pvData;
2911
+ py = V_ARRAY(&realargs[i])->pvData;
2912
+ pv = V_ARRAY(&realargs[i])->pvData;
2913
+ for (ent = 0; ent < (int)rgsabound[0].cElements; ent++)
2914
+ {
2915
+ VARIANT velem;
2916
+ VALUE elem = rb_ary_entry(param, ent);
2917
+ ole_val2variant(elem, &velem);
2918
+ if (v != VT_VARIANT)
2919
+ {
2920
+ VariantChangeTypeEx(&velem, &velem,
2921
+ cWIN32OLE_lcid, 0, v);
2922
+ }
2923
+ switch (v)
2924
+ {
2925
+ /* 128 bits */
2926
+ case VT_VARIANT:
2927
+ *pv++ = velem;
2928
+ break;
2929
+ /* 64 bits */
2930
+ case VT_R8:
2931
+ case VT_CY:
2932
+ case VT_DATE:
2933
+ *py++ = V_CY(&velem);
2934
+ break;
2935
+ /* 16 bits */
2936
+ case VT_BOOL:
2937
+ case VT_I2:
2938
+ case VT_UI2:
2939
+ *ps++ = V_I2(&velem);
2940
+ break;
2941
+ /* 8 bites */
2942
+ case VT_UI1:
2943
+ case VT_I1:
2944
+ *pb++ = V_UI1(&velem);
2945
+ break;
2946
+ /* 32 bits */
2947
+ default:
2948
+ *pl++ = V_I4(&velem);
2949
+ break;
2950
+ }
2951
+ }
2952
+ SafeArrayUnlock(V_ARRAY(&realargs[i]));
2953
+ }
2954
+ else
2955
+ {
2956
+ ole_val2variant(param, &realargs[i]);
2957
+ if ((vt & (~VT_BYREF)) != VT_VARIANT)
2958
+ {
2959
+ hr = VariantChangeTypeEx(&realargs[i], &realargs[i],
2960
+ cWIN32OLE_lcid, 0,
2961
+ (VARTYPE)(vt & (~VT_BYREF)));
2962
+ if (hr != S_OK)
2963
+ {
2964
+ rb_raise(rb_eTypeError, "not valid value");
2965
+ }
2966
+ }
2967
+ }
2968
+ if ((vt & VT_BYREF) || vt == VT_VARIANT)
2969
+ {
2970
+ if (vt == VT_VARIANT)
2971
+ V_VT(&dispParams.rgvarg[i]) = VT_VARIANT | VT_BYREF;
2972
+ switch (vt & (~VT_BYREF))
2973
+ {
2974
+ /* 128 bits */
2975
+ case VT_VARIANT:
2976
+ V_VARIANTREF(&dispParams.rgvarg[i]) = &realargs[i];
2977
+ break;
2978
+ /* 64 bits */
2979
+ case VT_R8:
2980
+ case VT_CY:
2981
+ case VT_DATE:
2982
+ V_CYREF(&dispParams.rgvarg[i]) = &V_CY(&realargs[i]);
2983
+ break;
2984
+ /* 16 bits */
2985
+ case VT_BOOL:
2986
+ case VT_I2:
2987
+ case VT_UI2:
2988
+ V_I2REF(&dispParams.rgvarg[i]) = &V_I2(&realargs[i]);
2989
+ break;
2990
+ /* 8 bites */
2991
+ case VT_UI1:
2992
+ case VT_I1:
2993
+ V_UI1REF(&dispParams.rgvarg[i]) = &V_UI1(&realargs[i]);
2994
+ break;
2995
+ /* 32 bits */
2996
+ default:
2997
+ V_I4REF(&dispParams.rgvarg[i]) = &V_I4(&realargs[i]);
2998
+ break;
2999
+ }
3000
+ }
3001
+ else
3002
+ {
3003
+ /* copy 64 bits of data */
3004
+ V_CY(&dispParams.rgvarg[i]) = V_CY(&realargs[i]);
3005
+ }
3006
+ }
3007
+ }
3008
+
3009
+ if (dispkind & DISPATCH_PROPERTYPUT) {
3010
+ dispParams.cNamedArgs = 1;
3011
+ dispParams.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
3012
+ dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
3013
+ }
3014
+
3015
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, RB_NUM2INT(dispid),
3016
+ &IID_NULL, cWIN32OLE_lcid,
3017
+ dispkind,
3018
+ &dispParams, &result,
3019
+ &excepinfo, &argErr);
3020
+
3021
+ if (FAILED(hr)) {
3022
+ v = ole_excepinfo2msg(&excepinfo);
3023
+ ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `<dispatch id:%d>': )%s",
3024
+ RB_NUM2INT(dispid),
3025
+ StringValuePtr(v));
3026
+ }
3027
+
3028
+ /* clear dispatch parameter */
3029
+ if(dispParams.cArgs > 0) {
3030
+ set_argv(realargs, 0, dispParams.cArgs);
3031
+ }
3032
+
3033
+ obj = ole_variant2val(&result);
3034
+ VariantClear(&result);
3035
+ return obj;
3036
+ }
3037
+
3038
+ /*
3039
+ * call-seq:
3040
+ * WIN32OLE#_invoke(dispid, args, types)
3041
+ *
3042
+ * Runs the early binding method.
3043
+ * The 1st argument specifies dispatch ID,
3044
+ * the 2nd argument specifies the array of arguments,
3045
+ * the 3rd argument specifies the array of the type of arguments.
3046
+ *
3047
+ * excel = WIN32OLE.new('Excel.Application')
3048
+ * excel._invoke(302, [], []) # same effect as excel.Quit
3049
+ */
3050
+ static VALUE
3051
+ fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3052
+ {
3053
+ return ole_invoke2(self, dispid, args, types, DISPATCH_METHOD);
3054
+ }
3055
+
3056
+ /*
3057
+ * call-seq:
3058
+ * WIN32OLE#_getproperty(dispid, args, types)
3059
+ *
3060
+ * Runs the early binding method to get property.
3061
+ * The 1st argument specifies dispatch ID,
3062
+ * the 2nd argument specifies the array of arguments,
3063
+ * the 3rd argument specifies the array of the type of arguments.
3064
+ *
3065
+ * excel = WIN32OLE.new('Excel.Application')
3066
+ * puts excel._getproperty(558, [], []) # same effect as puts excel.visible
3067
+ */
3068
+ static VALUE
3069
+ fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3070
+ {
3071
+ return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYGET);
3072
+ }
3073
+
3074
+ /*
3075
+ * call-seq:
3076
+ * WIN32OLE#_setproperty(dispid, args, types)
3077
+ *
3078
+ * Runs the early binding method to set property.
3079
+ * The 1st argument specifies dispatch ID,
3080
+ * the 2nd argument specifies the array of arguments,
3081
+ * the 3rd argument specifies the array of the type of arguments.
3082
+ *
3083
+ * excel = WIN32OLE.new('Excel.Application')
3084
+ * excel._setproperty(558, [true], [WIN32OLE::VARIANT::VT_BOOL]) # same effect as excel.visible = true
3085
+ */
3086
+ static VALUE
3087
+ fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3088
+ {
3089
+ return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYPUT);
3090
+ }
3091
+
3092
+ /*
3093
+ * call-seq:
3094
+ * WIN32OLE[a1, a2, ...]=val
3095
+ *
3096
+ * Sets the value to WIN32OLE object specified by a1, a2, ...
3097
+ *
3098
+ * dict = WIN32OLE.new('Scripting.Dictionary')
3099
+ * dict.add('ruby', 'RUBY')
3100
+ * dict['ruby'] = 'Ruby'
3101
+ * puts dict['ruby'] # => 'Ruby'
3102
+ *
3103
+ * Remark: You can not use this method to set the property value.
3104
+ *
3105
+ * excel = WIN32OLE.new('Excel.Application')
3106
+ * # excel['Visible'] = true # This is error !!!
3107
+ * excel.Visible = true # You should to use this style to set the property.
3108
+ *
3109
+ */
3110
+ static VALUE
3111
+ fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self)
3112
+ {
3113
+ VALUE v = ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, TRUE);
3114
+ if (v == rb_eNoMethodError) {
3115
+ return rb_call_super(argc, argv);
3116
+ }
3117
+ return v;
3118
+ }
3119
+
3120
+ /*
3121
+ * call-seq:
3122
+ * WIN32OLE.setproperty('property', [arg1, arg2,...] val)
3123
+ *
3124
+ * Sets property of OLE object.
3125
+ * When you want to set property with argument, you can use this method.
3126
+ *
3127
+ * excel = WIN32OLE.new('Excel.Application')
3128
+ * excel.Visible = true
3129
+ * book = excel.workbooks.add
3130
+ * sheet = book.worksheets(1)
3131
+ * sheet.setproperty('Cells', 1, 2, 10) # => The B1 cell value is 10.
3132
+ */
3133
+ static VALUE
3134
+ fole_setproperty(int argc, VALUE *argv, VALUE self)
3135
+ {
3136
+ VALUE v = ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, FALSE);
3137
+ if (v == rb_eNoMethodError) {
3138
+ return rb_call_super(argc, argv);
3139
+ }
3140
+ return v;
3141
+ }
3142
+
3143
+ /*
3144
+ * call-seq:
3145
+ * WIN32OLE[a1,a2,...]
3146
+ *
3147
+ * Returns the value of Collection specified by a1, a2,....
3148
+ *
3149
+ * dict = WIN32OLE.new('Scripting.Dictionary')
3150
+ * dict.add('ruby', 'Ruby')
3151
+ * puts dict['ruby'] # => 'Ruby' (same as `puts dict.item('ruby')')
3152
+ *
3153
+ * Remark: You can not use this method to get the property.
3154
+ * excel = WIN32OLE.new('Excel.Application')
3155
+ * # puts excel['Visible'] This is error !!!
3156
+ * puts excel.Visible # You should to use this style to get the property.
3157
+ *
3158
+ */
3159
+ static VALUE
3160
+ fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self)
3161
+ {
3162
+ VALUE v = ole_invoke(argc, argv, self, DISPATCH_PROPERTYGET, TRUE);
3163
+ if (v == rb_eNoMethodError) {
3164
+ return rb_call_super(argc, argv);
3165
+ }
3166
+ return v;
3167
+ }
3168
+
3169
+ static VALUE
3170
+ ole_propertyput(VALUE self, VALUE property, VALUE value)
3171
+ {
3172
+ struct oledata *pole = NULL;
3173
+ unsigned argErr;
3174
+ unsigned int index;
3175
+ HRESULT hr;
3176
+ EXCEPINFO excepinfo;
3177
+ DISPID dispID = DISPID_VALUE;
3178
+ DISPID dispIDParam = DISPID_PROPERTYPUT;
3179
+ USHORT wFlags = DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF;
3180
+ DISPPARAMS dispParams;
3181
+ VARIANTARG propertyValue[2];
3182
+ OLECHAR* pBuf[1];
3183
+ VALUE v;
3184
+ LCID lcid = cWIN32OLE_lcid;
3185
+ dispParams.rgdispidNamedArgs = &dispIDParam;
3186
+ dispParams.rgvarg = propertyValue;
3187
+ dispParams.cNamedArgs = 1;
3188
+ dispParams.cArgs = 1;
3189
+
3190
+ VariantInit(&propertyValue[0]);
3191
+ VariantInit(&propertyValue[1]);
3192
+ memset(&excepinfo, 0, sizeof(excepinfo));
3193
+
3194
+ pole = oledata_get_struct(self);
3195
+
3196
+ /* get ID from property name */
3197
+ pBuf[0] = ole_vstr2wc(property);
3198
+ hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, &IID_NULL,
3199
+ pBuf, 1, lcid, &dispID);
3200
+ SysFreeString(pBuf[0]);
3201
+ pBuf[0] = NULL;
3202
+
3203
+ if(FAILED(hr)) {
3204
+ ole_raise(hr, eWIN32OLERuntimeError,
3205
+ "unknown property or method: `%s'",
3206
+ StringValuePtr(property));
3207
+ }
3208
+ /* set property value */
3209
+ ole_val2variant(value, &propertyValue[0]);
3210
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, dispID, &IID_NULL,
3211
+ lcid, wFlags, &dispParams,
3212
+ NULL, &excepinfo, &argErr);
3213
+
3214
+ for(index = 0; index < dispParams.cArgs; ++index) {
3215
+ VariantClear(&propertyValue[index]);
3216
+ }
3217
+ if (FAILED(hr)) {
3218
+ v = ole_excepinfo2msg(&excepinfo);
3219
+ ole_raise(hr, eWIN32OLERuntimeError, "(in setting property `%s': )%s",
3220
+ StringValuePtr(property),
3221
+ StringValuePtr(v));
3222
+ }
3223
+ return Qnil;
3224
+ }
3225
+
3226
+ /*
3227
+ * call-seq:
3228
+ * WIN32OLE#ole_free
3229
+ *
3230
+ * invokes Release method of Dispatch interface of WIN32OLE object.
3231
+ * Usually, you do not need to call this method because Release method
3232
+ * called automatically when WIN32OLE object garbaged.
3233
+ *
3234
+ */
3235
+ static VALUE
3236
+ fole_free(VALUE self)
3237
+ {
3238
+ struct oledata *pole = NULL;
3239
+ pole = oledata_get_struct(self);
3240
+ OLE_FREE(pole->pDispatch);
3241
+ pole->pDispatch = NULL;
3242
+ return Qnil;
3243
+ }
3244
+
3245
+ static VALUE
3246
+ ole_each_sub(VALUE pEnumV)
3247
+ {
3248
+ VARIANT variant;
3249
+ VALUE obj = Qnil;
3250
+ IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
3251
+ VariantInit(&variant);
3252
+ while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) {
3253
+ obj = ole_variant2val(&variant);
3254
+ VariantClear(&variant);
3255
+ VariantInit(&variant);
3256
+ rb_yield(obj);
3257
+ }
3258
+ return Qnil;
3259
+ }
3260
+
3261
+ static VALUE
3262
+ ole_ienum_free(VALUE pEnumV)
3263
+ {
3264
+ IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
3265
+ OLE_RELEASE(pEnum);
3266
+ return Qnil;
3267
+ }
3268
+
3269
+ /*
3270
+ * call-seq:
3271
+ * WIN32OLE#each {|i|...}
3272
+ *
3273
+ * Iterates over each item of OLE collection which has IEnumVARIANT interface.
3274
+ *
3275
+ * excel = WIN32OLE.new('Excel.Application')
3276
+ * book = excel.workbooks.add
3277
+ * sheets = book.worksheets(1)
3278
+ * cells = sheets.cells("A1:A5")
3279
+ * cells.each do |cell|
3280
+ * cell.value = 10
3281
+ * end
3282
+ */
3283
+ static VALUE
3284
+ fole_each(VALUE self)
3285
+ {
3286
+ LCID lcid = cWIN32OLE_lcid;
3287
+
3288
+ struct oledata *pole = NULL;
3289
+
3290
+ unsigned int argErr;
3291
+ EXCEPINFO excepinfo;
3292
+ DISPPARAMS dispParams;
3293
+ VARIANT result;
3294
+ HRESULT hr;
3295
+ IEnumVARIANT *pEnum = NULL;
3296
+ void *p;
3297
+
3298
+ RETURN_ENUMERATOR(self, 0, 0);
3299
+
3300
+ VariantInit(&result);
3301
+ dispParams.rgvarg = NULL;
3302
+ dispParams.rgdispidNamedArgs = NULL;
3303
+ dispParams.cNamedArgs = 0;
3304
+ dispParams.cArgs = 0;
3305
+ memset(&excepinfo, 0, sizeof(excepinfo));
3306
+
3307
+ pole = oledata_get_struct(self);
3308
+ hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DISPID_NEWENUM,
3309
+ &IID_NULL, lcid,
3310
+ DISPATCH_METHOD | DISPATCH_PROPERTYGET,
3311
+ &dispParams, &result,
3312
+ &excepinfo, &argErr);
3313
+
3314
+ if (FAILED(hr)) {
3315
+ VariantClear(&result);
3316
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to get IEnum Interface");
3317
+ }
3318
+
3319
+ if (V_VT(&result) == VT_UNKNOWN) {
3320
+ hr = V_UNKNOWN(&result)->lpVtbl->QueryInterface(V_UNKNOWN(&result),
3321
+ &IID_IEnumVARIANT,
3322
+ &p);
3323
+ pEnum = p;
3324
+ } else if (V_VT(&result) == VT_DISPATCH) {
3325
+ hr = V_DISPATCH(&result)->lpVtbl->QueryInterface(V_DISPATCH(&result),
3326
+ &IID_IEnumVARIANT,
3327
+ &p);
3328
+ pEnum = p;
3329
+ }
3330
+ if (FAILED(hr) || !pEnum) {
3331
+ VariantClear(&result);
3332
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to get IEnum Interface");
3333
+ }
3334
+
3335
+ VariantClear(&result);
3336
+ rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum);
3337
+ return Qnil;
3338
+ }
3339
+
3340
+ /*
3341
+ * call-seq:
3342
+ * WIN32OLE#method_missing(id [,arg1, arg2, ...])
3343
+ *
3344
+ * Calls WIN32OLE#invoke method.
3345
+ */
3346
+ static VALUE
3347
+ fole_missing(int argc, VALUE *argv, VALUE self)
3348
+ {
3349
+ VALUE mid, org_mid, sym, v;
3350
+ const char* mname;
3351
+ long n;
3352
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
3353
+ mid = org_mid = argv[0];
3354
+ sym = rb_check_symbol(&mid);
3355
+ if (!NIL_P(sym)) mid = rb_sym2str(sym);
3356
+ mname = StringValueCStr(mid);
3357
+ if(!mname) {
3358
+ rb_raise(rb_eRuntimeError, "fail: unknown method or property");
3359
+ }
3360
+ n = RSTRING_LEN(mid);
3361
+ if(mname[n-1] == '=') {
3362
+ rb_check_arity(argc, 2, 2);
3363
+ argv[0] = rb_enc_associate(rb_str_subseq(mid, 0, n-1), cWIN32OLE_enc);
3364
+
3365
+ return ole_propertyput(self, argv[0], argv[1]);
3366
+ }
3367
+ else {
3368
+ argv[0] = rb_enc_associate(rb_str_dup(mid), cWIN32OLE_enc);
3369
+ v = ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
3370
+ if (v == rb_eNoMethodError) {
3371
+ argv[0] = org_mid;
3372
+ return rb_call_super(argc, argv);
3373
+ }
3374
+ return v;
3375
+ }
3376
+ }
3377
+
3378
+ static HRESULT
3379
+ typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti)
3380
+ {
3381
+ ITypeInfo *pTypeInfo;
3382
+ ITypeLib *pTypeLib;
3383
+ BSTR bstr;
3384
+ VALUE type;
3385
+ UINT i;
3386
+ UINT count;
3387
+ LCID lcid = cWIN32OLE_lcid;
3388
+ HRESULT hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
3389
+ 0, lcid, &pTypeInfo);
3390
+ if(FAILED(hr)) {
3391
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
3392
+ }
3393
+ hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo,
3394
+ -1,
3395
+ &bstr,
3396
+ NULL, NULL, NULL);
3397
+ type = WC2VSTR(bstr);
3398
+ hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
3399
+ OLE_RELEASE(pTypeInfo);
3400
+ if (FAILED(hr)) {
3401
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetContainingTypeLib");
3402
+ }
3403
+ count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
3404
+ for (i = 0; i < count; i++) {
3405
+ hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
3406
+ &bstr, NULL, NULL, NULL);
3407
+ if (SUCCEEDED(hr) && rb_str_cmp(WC2VSTR(bstr), type) == 0) {
3408
+ hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
3409
+ if (SUCCEEDED(hr)) {
3410
+ *ppti = pTypeInfo;
3411
+ break;
3412
+ }
3413
+ }
3414
+ }
3415
+ OLE_RELEASE(pTypeLib);
3416
+ return hr;
3417
+ }
3418
+
3419
+ static VALUE
3420
+ ole_methods(VALUE self, int mask)
3421
+ {
3422
+ ITypeInfo *pTypeInfo;
3423
+ HRESULT hr;
3424
+ VALUE methods;
3425
+ struct oledata *pole = NULL;
3426
+
3427
+ pole = oledata_get_struct(self);
3428
+ methods = rb_ary_new();
3429
+
3430
+ hr = typeinfo_from_ole(pole, &pTypeInfo);
3431
+ if(FAILED(hr))
3432
+ return methods;
3433
+ rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask));
3434
+ OLE_RELEASE(pTypeInfo);
3435
+ return methods;
3436
+ }
3437
+
3438
+ /*
3439
+ * call-seq:
3440
+ * WIN32OLE#ole_methods
3441
+ *
3442
+ * Returns the array of WIN32OLE_METHOD object.
3443
+ * The element is OLE method of WIN32OLE object.
3444
+ *
3445
+ * excel = WIN32OLE.new('Excel.Application')
3446
+ * methods = excel.ole_methods
3447
+ *
3448
+ */
3449
+ static VALUE
3450
+ fole_methods(VALUE self)
3451
+ {
3452
+ return ole_methods( self, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
3453
+ }
3454
+
3455
+ /*
3456
+ * call-seq:
3457
+ * WIN32OLE#ole_get_methods
3458
+ *
3459
+ * Returns the array of WIN32OLE_METHOD object .
3460
+ * The element of the array is property (gettable) of WIN32OLE object.
3461
+ *
3462
+ * excel = WIN32OLE.new('Excel.Application')
3463
+ * properties = excel.ole_get_methods
3464
+ */
3465
+ static VALUE
3466
+ fole_get_methods(VALUE self)
3467
+ {
3468
+ return ole_methods( self, INVOKE_PROPERTYGET);
3469
+ }
3470
+
3471
+ /*
3472
+ * call-seq:
3473
+ * WIN32OLE#ole_put_methods
3474
+ *
3475
+ * Returns the array of WIN32OLE_METHOD object .
3476
+ * The element of the array is property (settable) of WIN32OLE object.
3477
+ *
3478
+ * excel = WIN32OLE.new('Excel.Application')
3479
+ * properties = excel.ole_put_methods
3480
+ */
3481
+ static VALUE
3482
+ fole_put_methods(VALUE self)
3483
+ {
3484
+ return ole_methods( self, INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF);
3485
+ }
3486
+
3487
+ /*
3488
+ * call-seq:
3489
+ * WIN32OLE#ole_func_methods
3490
+ *
3491
+ * Returns the array of WIN32OLE_METHOD object .
3492
+ * The element of the array is property (settable) of WIN32OLE object.
3493
+ *
3494
+ * excel = WIN32OLE.new('Excel.Application')
3495
+ * properties = excel.ole_func_methods
3496
+ *
3497
+ */
3498
+ static VALUE
3499
+ fole_func_methods(VALUE self)
3500
+ {
3501
+ return ole_methods( self, INVOKE_FUNC);
3502
+ }
3503
+
3504
+ /*
3505
+ * call-seq:
3506
+ * WIN32OLE#ole_type
3507
+ *
3508
+ * Returns WIN32OLE_TYPE object.
3509
+ *
3510
+ * excel = WIN32OLE.new('Excel.Application')
3511
+ * tobj = excel.ole_type
3512
+ */
3513
+ static VALUE
3514
+ fole_type(VALUE self)
3515
+ {
3516
+ ITypeInfo *pTypeInfo;
3517
+ HRESULT hr;
3518
+ struct oledata *pole = NULL;
3519
+ LCID lcid = cWIN32OLE_lcid;
3520
+ VALUE type = Qnil;
3521
+
3522
+ pole = oledata_get_struct(self);
3523
+
3524
+ hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo );
3525
+ if(FAILED(hr)) {
3526
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
3527
+ }
3528
+ type = ole_type_from_itypeinfo(pTypeInfo);
3529
+ OLE_RELEASE(pTypeInfo);
3530
+ if (type == Qnil) {
3531
+ rb_raise(rb_eRuntimeError, "failed to create WIN32OLE_TYPE obj from ITypeInfo");
3532
+ }
3533
+ return type;
3534
+ }
3535
+
3536
+ /*
3537
+ * call-seq:
3538
+ * WIN32OLE#ole_typelib -> The WIN32OLE_TYPELIB object
3539
+ *
3540
+ * Returns the WIN32OLE_TYPELIB object. The object represents the
3541
+ * type library which contains the WIN32OLE object.
3542
+ *
3543
+ * excel = WIN32OLE.new('Excel.Application')
3544
+ * tlib = excel.ole_typelib
3545
+ * puts tlib.name # -> 'Microsoft Excel 9.0 Object Library'
3546
+ */
3547
+ static VALUE
3548
+ fole_typelib(VALUE self)
3549
+ {
3550
+ struct oledata *pole = NULL;
3551
+ HRESULT hr;
3552
+ ITypeInfo *pTypeInfo;
3553
+ LCID lcid = cWIN32OLE_lcid;
3554
+ VALUE vtlib = Qnil;
3555
+
3556
+ pole = oledata_get_struct(self);
3557
+ hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
3558
+ 0, lcid, &pTypeInfo);
3559
+ if(FAILED(hr)) {
3560
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
3561
+ }
3562
+ vtlib = ole_typelib_from_itypeinfo(pTypeInfo);
3563
+ OLE_RELEASE(pTypeInfo);
3564
+ if (vtlib == Qnil) {
3565
+ rb_raise(rb_eRuntimeError, "failed to get type library info.");
3566
+ }
3567
+ return vtlib;
3568
+ }
3569
+
3570
+ /*
3571
+ * call-seq:
3572
+ * WIN32OLE#ole_query_interface(iid) -> WIN32OLE object
3573
+ *
3574
+ * Returns WIN32OLE object for a specific dispatch or dual
3575
+ * interface specified by iid.
3576
+ *
3577
+ * ie = WIN32OLE.new('InternetExplorer.Application')
3578
+ * ie_web_app = ie.ole_query_interface('{0002DF05-0000-0000-C000-000000000046}') # => WIN32OLE object for dispinterface IWebBrowserApp
3579
+ */
3580
+ static VALUE
3581
+ fole_query_interface(VALUE self, VALUE str_iid)
3582
+ {
3583
+ HRESULT hr;
3584
+ OLECHAR *pBuf;
3585
+ IID iid;
3586
+ struct oledata *pole = NULL;
3587
+ IDispatch *pDispatch;
3588
+ void *p;
3589
+
3590
+ pBuf = ole_vstr2wc(str_iid);
3591
+ hr = CLSIDFromString(pBuf, &iid);
3592
+ SysFreeString(pBuf);
3593
+ if(FAILED(hr)) {
3594
+ ole_raise(hr, eWIN32OLERuntimeError,
3595
+ "invalid iid: `%s'",
3596
+ StringValuePtr(str_iid));
3597
+ }
3598
+
3599
+ pole = oledata_get_struct(self);
3600
+ if(!pole->pDispatch) {
3601
+ rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
3602
+ }
3603
+
3604
+ hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &iid,
3605
+ &p);
3606
+ if(FAILED(hr)) {
3607
+ ole_raise(hr, eWIN32OLEQueryInterfaceError,
3608
+ "failed to get interface `%s'",
3609
+ StringValuePtr(str_iid));
3610
+ }
3611
+
3612
+ pDispatch = p;
3613
+ return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
3614
+ }
3615
+
3616
+ /*
3617
+ * call-seq:
3618
+ * WIN32OLE#ole_respond_to?(method) -> true or false
3619
+ *
3620
+ * Returns true when OLE object has OLE method, otherwise returns false.
3621
+ *
3622
+ * ie = WIN32OLE.new('InternetExplorer.Application')
3623
+ * ie.ole_respond_to?("gohome") => true
3624
+ */
3625
+ static VALUE
3626
+ fole_respond_to(VALUE self, VALUE method)
3627
+ {
3628
+ struct oledata *pole = NULL;
3629
+ BSTR wcmdname;
3630
+ DISPID DispID;
3631
+ HRESULT hr;
3632
+ if(!RB_TYPE_P(method, T_STRING) && !RB_TYPE_P(method, T_SYMBOL)) {
3633
+ rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
3634
+ }
3635
+ if (RB_TYPE_P(method, T_SYMBOL)) {
3636
+ method = rb_sym2str(method);
3637
+ }
3638
+ pole = oledata_get_struct(self);
3639
+ wcmdname = ole_vstr2wc(method);
3640
+ hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
3641
+ &wcmdname, 1, cWIN32OLE_lcid, &DispID);
3642
+ SysFreeString(wcmdname);
3643
+ return SUCCEEDED(hr) ? Qtrue : Qfalse;
3644
+ }
3645
+
3646
+ HRESULT
3647
+ ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile)
3648
+ {
3649
+ HRESULT hr;
3650
+ ITypeLib *pTypeLib;
3651
+ UINT i;
3652
+
3653
+ hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
3654
+ if (FAILED(hr)) {
3655
+ return hr;
3656
+ }
3657
+
3658
+ hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
3659
+ name, helpstr,
3660
+ helpcontext, helpfile);
3661
+ if (FAILED(hr)) {
3662
+ OLE_RELEASE(pTypeLib);
3663
+ return hr;
3664
+ }
3665
+ OLE_RELEASE(pTypeLib);
3666
+ return hr;
3667
+ }
3668
+
3669
+ static VALUE
3670
+ ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
3671
+ {
3672
+ HRESULT hr;
3673
+ BSTR bstr;
3674
+ ITypeInfo *pRefTypeInfo;
3675
+ VALUE type = Qnil;
3676
+
3677
+ hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
3678
+ V_UNION1(pTypeDesc, hreftype),
3679
+ &pRefTypeInfo);
3680
+ if(FAILED(hr))
3681
+ return Qnil;
3682
+ hr = ole_docinfo_from_type(pRefTypeInfo, &bstr, NULL, NULL, NULL);
3683
+ if(FAILED(hr)) {
3684
+ OLE_RELEASE(pRefTypeInfo);
3685
+ return Qnil;
3686
+ }
3687
+ OLE_RELEASE(pRefTypeInfo);
3688
+ type = WC2VSTR(bstr);
3689
+ if(typedetails != Qnil)
3690
+ rb_ary_push(typedetails, type);
3691
+ return type;
3692
+ }
3693
+
3694
+ static VALUE
3695
+ ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
3696
+ {
3697
+ TYPEDESC *p = pTypeDesc;
3698
+ VALUE type = rb_str_new2("");
3699
+
3700
+ if (p->vt == VT_PTR || p->vt == VT_SAFEARRAY) {
3701
+ p = V_UNION1(p, lptdesc);
3702
+ type = ole_typedesc2val(pTypeInfo, p, typedetails);
3703
+ }
3704
+ return type;
3705
+ }
3706
+
3707
+ VALUE
3708
+ ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
3709
+ {
3710
+ VALUE str;
3711
+ VALUE typestr = Qnil;
3712
+ switch(pTypeDesc->vt) {
3713
+ case VT_I2:
3714
+ typestr = rb_str_new2("I2");
3715
+ break;
3716
+ case VT_I4:
3717
+ typestr = rb_str_new2("I4");
3718
+ break;
3719
+ case VT_R4:
3720
+ typestr = rb_str_new2("R4");
3721
+ break;
3722
+ case VT_R8:
3723
+ typestr = rb_str_new2("R8");
3724
+ break;
3725
+ case VT_CY:
3726
+ typestr = rb_str_new2("CY");
3727
+ break;
3728
+ case VT_DATE:
3729
+ typestr = rb_str_new2("DATE");
3730
+ break;
3731
+ case VT_BSTR:
3732
+ typestr = rb_str_new2("BSTR");
3733
+ break;
3734
+ case VT_BOOL:
3735
+ typestr = rb_str_new2("BOOL");
3736
+ break;
3737
+ case VT_VARIANT:
3738
+ typestr = rb_str_new2("VARIANT");
3739
+ break;
3740
+ case VT_DECIMAL:
3741
+ typestr = rb_str_new2("DECIMAL");
3742
+ break;
3743
+ case VT_I1:
3744
+ typestr = rb_str_new2("I1");
3745
+ break;
3746
+ case VT_UI1:
3747
+ typestr = rb_str_new2("UI1");
3748
+ break;
3749
+ case VT_UI2:
3750
+ typestr = rb_str_new2("UI2");
3751
+ break;
3752
+ case VT_UI4:
3753
+ typestr = rb_str_new2("UI4");
3754
+ break;
3755
+ #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
3756
+ case VT_I8:
3757
+ typestr = rb_str_new2("I8");
3758
+ break;
3759
+ case VT_UI8:
3760
+ typestr = rb_str_new2("UI8");
3761
+ break;
3762
+ #endif
3763
+ case VT_INT:
3764
+ typestr = rb_str_new2("INT");
3765
+ break;
3766
+ case VT_UINT:
3767
+ typestr = rb_str_new2("UINT");
3768
+ break;
3769
+ case VT_VOID:
3770
+ typestr = rb_str_new2("VOID");
3771
+ break;
3772
+ case VT_HRESULT:
3773
+ typestr = rb_str_new2("HRESULT");
3774
+ break;
3775
+ case VT_PTR:
3776
+ typestr = rb_str_new2("PTR");
3777
+ if(typedetails != Qnil)
3778
+ rb_ary_push(typedetails, typestr);
3779
+ return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
3780
+ case VT_SAFEARRAY:
3781
+ typestr = rb_str_new2("SAFEARRAY");
3782
+ if(typedetails != Qnil)
3783
+ rb_ary_push(typedetails, typestr);
3784
+ return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
3785
+ case VT_CARRAY:
3786
+ typestr = rb_str_new2("CARRAY");
3787
+ break;
3788
+ case VT_USERDEFINED:
3789
+ typestr = rb_str_new2("USERDEFINED");
3790
+ if (typedetails != Qnil)
3791
+ rb_ary_push(typedetails, typestr);
3792
+ str = ole_usertype2val(pTypeInfo, pTypeDesc, typedetails);
3793
+ if (str != Qnil) {
3794
+ return str;
3795
+ }
3796
+ return typestr;
3797
+ case VT_UNKNOWN:
3798
+ typestr = rb_str_new2("UNKNOWN");
3799
+ break;
3800
+ case VT_DISPATCH:
3801
+ typestr = rb_str_new2("DISPATCH");
3802
+ break;
3803
+ case VT_ERROR:
3804
+ typestr = rb_str_new2("ERROR");
3805
+ break;
3806
+ case VT_LPWSTR:
3807
+ typestr = rb_str_new2("LPWSTR");
3808
+ break;
3809
+ case VT_LPSTR:
3810
+ typestr = rb_str_new2("LPSTR");
3811
+ break;
3812
+ case VT_RECORD:
3813
+ typestr = rb_str_new2("RECORD");
3814
+ break;
3815
+ default:
3816
+ typestr = rb_str_new2("Unknown Type ");
3817
+ rb_str_concat(typestr, rb_fix2str(RB_INT2FIX(pTypeDesc->vt), 10));
3818
+ break;
3819
+ }
3820
+ if (typedetails != Qnil)
3821
+ rb_ary_push(typedetails, typestr);
3822
+ return typestr;
3823
+ }
3824
+
3825
+ /*
3826
+ * call-seq:
3827
+ * WIN32OLE#ole_method_help(method)
3828
+ *
3829
+ * Returns WIN32OLE_METHOD object corresponding with method
3830
+ * specified by 1st argument.
3831
+ *
3832
+ * excel = WIN32OLE.new('Excel.Application')
3833
+ * method = excel.ole_method_help('Quit')
3834
+ *
3835
+ */
3836
+ static VALUE
3837
+ fole_method_help(VALUE self, VALUE cmdname)
3838
+ {
3839
+ ITypeInfo *pTypeInfo;
3840
+ HRESULT hr;
3841
+ struct oledata *pole = NULL;
3842
+ VALUE obj;
3843
+
3844
+ SafeStringValue(cmdname);
3845
+ pole = oledata_get_struct(self);
3846
+ hr = typeinfo_from_ole(pole, &pTypeInfo);
3847
+ if(FAILED(hr))
3848
+ ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to get ITypeInfo");
3849
+
3850
+ obj = create_win32ole_method(pTypeInfo, cmdname);
3851
+
3852
+ OLE_RELEASE(pTypeInfo);
3853
+ if (obj == Qnil)
3854
+ rb_raise(eWIN32OLERuntimeError, "not found %s",
3855
+ StringValuePtr(cmdname));
3856
+ return obj;
3857
+ }
3858
+
3859
+ /*
3860
+ * call-seq:
3861
+ * WIN32OLE#ole_activex_initialize() -> Qnil
3862
+ *
3863
+ * Initialize WIN32OLE object(ActiveX Control) by calling
3864
+ * IPersistMemory::InitNew.
3865
+ *
3866
+ * Before calling OLE method, some kind of the ActiveX controls
3867
+ * created with MFC should be initialized by calling
3868
+ * IPersistXXX::InitNew.
3869
+ *
3870
+ * If and only if you received the exception "HRESULT error code:
3871
+ * 0x8000ffff catastrophic failure", try this method before
3872
+ * invoking any ole_method.
3873
+ *
3874
+ * obj = WIN32OLE.new("ProgID_or_GUID_of_ActiveX_Control")
3875
+ * obj.ole_activex_initialize
3876
+ * obj.method(...)
3877
+ *
3878
+ */
3879
+ static VALUE
3880
+ fole_activex_initialize(VALUE self)
3881
+ {
3882
+ struct oledata *pole = NULL;
3883
+ IPersistMemory *pPersistMemory;
3884
+ void *p;
3885
+
3886
+ HRESULT hr = S_OK;
3887
+
3888
+ pole = oledata_get_struct(self);
3889
+
3890
+ hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p);
3891
+ pPersistMemory = p;
3892
+ if (SUCCEEDED(hr)) {
3893
+ hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory);
3894
+ OLE_RELEASE(pPersistMemory);
3895
+ if (SUCCEEDED(hr)) {
3896
+ return Qnil;
3897
+ }
3898
+ }
3899
+
3900
+ if (FAILED(hr)) {
3901
+ ole_raise(hr, eWIN32OLERuntimeError, "fail to initialize ActiveX control");
3902
+ }
3903
+
3904
+ return Qnil;
3905
+ }
3906
+
3907
+ HRESULT
3908
+ typelib_from_val(VALUE obj, ITypeLib **pTypeLib)
3909
+ {
3910
+ LCID lcid = cWIN32OLE_lcid;
3911
+ HRESULT hr;
3912
+ struct oledata *pole = NULL;
3913
+ unsigned int index;
3914
+ ITypeInfo *pTypeInfo;
3915
+ pole = oledata_get_struct(obj);
3916
+ hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
3917
+ 0, lcid, &pTypeInfo);
3918
+ if (FAILED(hr)) {
3919
+ return hr;
3920
+ }
3921
+ hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, pTypeLib, &index);
3922
+ OLE_RELEASE(pTypeInfo);
3923
+ return hr;
3924
+ }
3925
+
3926
+ static void
3927
+ com_hash_free(void *ptr)
3928
+ {
3929
+ st_table *tbl = ptr;
3930
+ st_free_table(tbl);
3931
+ }
3932
+
3933
+ static void
3934
+ com_hash_mark(void *ptr)
3935
+ {
3936
+ st_table *tbl = ptr;
3937
+ rb_mark_hash(tbl);
3938
+ }
3939
+
3940
+ static size_t
3941
+ com_hash_size(const void *ptr)
3942
+ {
3943
+ const st_table *tbl = ptr;
3944
+ return st_memsize(tbl);
3945
+ }
3946
+
3947
+ static void
3948
+ check_nano_server(void)
3949
+ {
3950
+ HKEY hsubkey;
3951
+ LONG err;
3952
+ const char * subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Server\\ServerLevels";
3953
+ const char * regval = "NanoServer";
3954
+
3955
+ err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subkey, 0, KEY_READ, &hsubkey);
3956
+ if (err == ERROR_SUCCESS) {
3957
+ err = RegQueryValueEx(hsubkey, regval, NULL, NULL, NULL, NULL);
3958
+ if (err == ERROR_SUCCESS) {
3959
+ g_running_nano = TRUE;
3960
+ }
3961
+ RegCloseKey(hsubkey);
3962
+ }
3963
+ }
3964
+
3965
+
3966
+ void
3967
+ Init_win32ole(void)
3968
+ {
3969
+ cWIN32OLE_lcid = LOCALE_SYSTEM_DEFAULT;
3970
+ g_ole_initialized_init();
3971
+ check_nano_server();
3972
+
3973
+ com_vtbl.QueryInterface = QueryInterface;
3974
+ com_vtbl.AddRef = AddRef;
3975
+ com_vtbl.Release = Release;
3976
+ com_vtbl.GetTypeInfoCount = GetTypeInfoCount;
3977
+ com_vtbl.GetTypeInfo = GetTypeInfo;
3978
+ com_vtbl.GetIDsOfNames = GetIDsOfNames;
3979
+ com_vtbl.Invoke = Invoke;
3980
+
3981
+ message_filter.QueryInterface = mf_QueryInterface;
3982
+ message_filter.AddRef = mf_AddRef;
3983
+ message_filter.Release = mf_Release;
3984
+ message_filter.HandleInComingCall = mf_HandleInComingCall;
3985
+ message_filter.RetryRejectedCall = mf_RetryRejectedCall;
3986
+ message_filter.MessagePending = mf_MessagePending;
3987
+
3988
+ enc2cp_hash = TypedData_Wrap_Struct(0, &win32ole_hash_datatype, 0);
3989
+ RTYPEDDATA_DATA(enc2cp_hash) = st_init_numtable();
3990
+ rb_gc_register_mark_object(enc2cp_hash);
3991
+
3992
+ com_hash = TypedData_Wrap_Struct(0, &win32ole_hash_datatype, 0);
3993
+ RTYPEDDATA_DATA(com_hash) = st_init_numtable();
3994
+ rb_gc_register_mark_object(com_hash);
3995
+
3996
+ cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
3997
+
3998
+ rb_define_alloc_func(cWIN32OLE, fole_s_allocate);
3999
+
4000
+ rb_define_method(cWIN32OLE, "initialize", fole_initialize, -1);
4001
+
4002
+ rb_define_singleton_method(cWIN32OLE, "connect", fole_s_connect, -1);
4003
+ rb_define_singleton_method(cWIN32OLE, "const_load", fole_s_const_load, -1);
4004
+
4005
+ rb_define_singleton_method(cWIN32OLE, "ole_free", fole_s_free, 1);
4006
+ rb_define_singleton_method(cWIN32OLE, "ole_reference_count", fole_s_reference_count, 1);
4007
+ rb_define_singleton_method(cWIN32OLE, "ole_show_help", fole_s_show_help, -1);
4008
+ rb_define_singleton_method(cWIN32OLE, "codepage", fole_s_get_code_page, 0);
4009
+ rb_define_singleton_method(cWIN32OLE, "codepage=", fole_s_set_code_page, 1);
4010
+ rb_define_singleton_method(cWIN32OLE, "locale", fole_s_get_locale, 0);
4011
+ rb_define_singleton_method(cWIN32OLE, "locale=", fole_s_set_locale, 1);
4012
+ rb_define_singleton_method(cWIN32OLE, "create_guid", fole_s_create_guid, 0);
4013
+ rb_define_singleton_method(cWIN32OLE, "ole_initialize", fole_s_ole_initialize, 0);
4014
+ rb_define_singleton_method(cWIN32OLE, "ole_uninitialize", fole_s_ole_uninitialize, 0);
4015
+
4016
+ rb_define_method(cWIN32OLE, "invoke", fole_invoke, -1);
4017
+ rb_define_method(cWIN32OLE, "[]", fole_getproperty_with_bracket, -1);
4018
+ rb_define_method(cWIN32OLE, "_invoke", fole_invoke2, 3);
4019
+ rb_define_method(cWIN32OLE, "_getproperty", fole_getproperty2, 3);
4020
+ rb_define_method(cWIN32OLE, "_setproperty", fole_setproperty2, 3);
4021
+
4022
+ /* support propput method that takes an argument */
4023
+ rb_define_method(cWIN32OLE, "[]=", fole_setproperty_with_bracket, -1);
4024
+
4025
+ rb_define_method(cWIN32OLE, "ole_free", fole_free, 0);
4026
+
4027
+ rb_define_method(cWIN32OLE, "each", fole_each, 0);
4028
+ rb_define_method(cWIN32OLE, "method_missing", fole_missing, -1);
4029
+
4030
+ /* support setproperty method much like Perl ;-) */
4031
+ rb_define_method(cWIN32OLE, "setproperty", fole_setproperty, -1);
4032
+
4033
+ rb_define_method(cWIN32OLE, "ole_methods", fole_methods, 0);
4034
+ rb_define_method(cWIN32OLE, "ole_get_methods", fole_get_methods, 0);
4035
+ rb_define_method(cWIN32OLE, "ole_put_methods", fole_put_methods, 0);
4036
+ rb_define_method(cWIN32OLE, "ole_func_methods", fole_func_methods, 0);
4037
+
4038
+ rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1);
4039
+ rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method");
4040
+ rb_define_method(cWIN32OLE, "ole_activex_initialize", fole_activex_initialize, 0);
4041
+ rb_define_method(cWIN32OLE, "ole_type", fole_type, 0);
4042
+ rb_define_alias(cWIN32OLE, "ole_obj_help", "ole_type");
4043
+ rb_define_method(cWIN32OLE, "ole_typelib", fole_typelib, 0);
4044
+ rb_define_method(cWIN32OLE, "ole_query_interface", fole_query_interface, 1);
4045
+ rb_define_method(cWIN32OLE, "ole_respond_to?", fole_respond_to, 1);
4046
+
4047
+ /* Constants definition */
4048
+
4049
+ /*
4050
+ * Version string of WIN32OLE.
4051
+ */
4052
+ rb_define_const(cWIN32OLE, "VERSION", rb_str_new2(WIN32OLE_VERSION));
4053
+
4054
+ /*
4055
+ * After invoking OLE methods with reference arguments, you can access
4056
+ * the value of arguments by using ARGV.
4057
+ *
4058
+ * If the method of OLE(COM) server written by C#.NET is following:
4059
+ *
4060
+ * void calcsum(int a, int b, out int c) {
4061
+ * c = a + b;
4062
+ * }
4063
+ *
4064
+ * then, the Ruby OLE(COM) client script to retrieve the value of
4065
+ * argument c after invoking calcsum method is following:
4066
+ *
4067
+ * a = 10
4068
+ * b = 20
4069
+ * c = 0
4070
+ * comserver.calcsum(a, b, c)
4071
+ * p c # => 0
4072
+ * p WIN32OLE::ARGV # => [10, 20, 30]
4073
+ *
4074
+ * You can use WIN32OLE_VARIANT object to retrieve the value of reference
4075
+ * arguments instead of referring WIN32OLE::ARGV.
4076
+ *
4077
+ */
4078
+ rb_define_const(cWIN32OLE, "ARGV", rb_ary_new());
4079
+
4080
+ /*
4081
+ * 0: ANSI code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4082
+ */
4083
+ rb_define_const(cWIN32OLE, "CP_ACP", RB_INT2FIX(CP_ACP));
4084
+
4085
+ /*
4086
+ * 1: OEM code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4087
+ */
4088
+ rb_define_const(cWIN32OLE, "CP_OEMCP", RB_INT2FIX(CP_OEMCP));
4089
+
4090
+ /*
4091
+ * 2
4092
+ */
4093
+ rb_define_const(cWIN32OLE, "CP_MACCP", RB_INT2FIX(CP_MACCP));
4094
+
4095
+ /*
4096
+ * 3: current thread ANSI code page. See WIN32OLE.codepage and
4097
+ * WIN32OLE.codepage=.
4098
+ */
4099
+ rb_define_const(cWIN32OLE, "CP_THREAD_ACP", RB_INT2FIX(CP_THREAD_ACP));
4100
+
4101
+ /*
4102
+ * 42: symbol code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4103
+ */
4104
+ rb_define_const(cWIN32OLE, "CP_SYMBOL", RB_INT2FIX(CP_SYMBOL));
4105
+
4106
+ /*
4107
+ * 65000: UTF-7 code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4108
+ */
4109
+ rb_define_const(cWIN32OLE, "CP_UTF7", RB_INT2FIX(CP_UTF7));
4110
+
4111
+ /*
4112
+ * 65001: UTF-8 code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4113
+ */
4114
+ rb_define_const(cWIN32OLE, "CP_UTF8", RB_INT2FIX(CP_UTF8));
4115
+
4116
+ /*
4117
+ * 0x0800: default locale for the operating system. See WIN32OLE.locale
4118
+ * and WIN32OLE.locale=.
4119
+ */
4120
+ rb_define_const(cWIN32OLE, "LOCALE_SYSTEM_DEFAULT", RB_INT2FIX(LOCALE_SYSTEM_DEFAULT));
4121
+
4122
+ /*
4123
+ * 0x0400: default locale for the user or process. See WIN32OLE.locale
4124
+ * and WIN32OLE.locale=.
4125
+ */
4126
+ rb_define_const(cWIN32OLE, "LOCALE_USER_DEFAULT", RB_INT2FIX(LOCALE_USER_DEFAULT));
4127
+
4128
+ Init_win32ole_variant_m();
4129
+ Init_win32ole_typelib();
4130
+ Init_win32ole_type();
4131
+ Init_win32ole_variable();
4132
+ Init_win32ole_method();
4133
+ Init_win32ole_param();
4134
+ Init_win32ole_event();
4135
+ Init_win32ole_variant();
4136
+ Init_win32ole_record();
4137
+ Init_win32ole_error();
4138
+
4139
+ ole_init_cp();
4140
+ }