Ruby  1.9.3p392(2013-02-22revision39386)
win32ole.c
Go to the documentation of this file.
1 /*
2  * (c) 1995 Microsoft Corporation. All rights reserved.
3  * Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
4  *
5  * Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy
6  * <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net>
7  *
8  * You may distribute under the terms of either the GNU General Public
9  * License or the Artistic License, as specified in the README file
10  * of the Perl distribution.
11  *
12  */
13 
14 /*
15  modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp>
16  */
17 
18 #include "ruby/ruby.h"
19 #include "ruby/st.h"
20 #include "ruby/encoding.h"
21 
22 #define GNUC_OLDER_3_4_4 \
23  ((__GNUC__ < 3) || \
24  ((__GNUC__ <= 3) && (__GNUC_MINOR__ < 4)) || \
25  ((__GNUC__ <= 3) && (__GNUC_MINOR__ <= 4) && (__GNUC_PATCHLEVEL__ <= 4)))
26 
27 #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
28 #ifndef NONAMELESSUNION
29 #define NONAMELESSUNION 1
30 #endif
31 #endif
32 
33 #include <ctype.h>
34 
35 #include <windows.h>
36 #include <ocidl.h>
37 #include <olectl.h>
38 #include <ole2.h>
39 #if defined(HAVE_TYPE_IMULTILANGUAGE2) || defined(HAVE_TYPE_IMULTILANGUAGE)
40 #include <mlang.h>
41 #endif
42 #include <stdlib.h>
43 #include <math.h>
44 #ifdef HAVE_STDARG_PROTOTYPES
45 #include <stdarg.h>
46 #define va_init_list(a,b) va_start(a,b)
47 #else
48 #include <varargs.h>
49 #define va_init_list(a,b) va_start(a)
50 #endif
51 #include <objidl.h>
52 
53 #define DOUT fprintf(stderr,"[%d]\n",__LINE__)
54 #define DOUTS(x) fprintf(stderr,"[%d]:" #x "=%s\n",__LINE__,x)
55 #define DOUTMSG(x) fprintf(stderr, "[%d]:" #x "\n",__LINE__)
56 #define DOUTI(x) fprintf(stderr, "[%ld]:" #x "=%d\n",__LINE__,x)
57 #define DOUTD(x) fprintf(stderr, "[%d]:" #x "=%f\n",__LINE__,x)
58 
59 #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
60 #define V_UNION1(X, Y) ((X)->u.Y)
61 #else
62 #define V_UNION1(X, Y) ((X)->Y)
63 #endif
64 
65 #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
66 #undef V_UNION
67 #define V_UNION(X,Y) ((X)->n1.n2.n3.Y)
68 
69 #undef V_VT
70 #define V_VT(X) ((X)->n1.n2.vt)
71 
72 #undef V_BOOL
73 #define V_BOOL(X) V_UNION(X,boolVal)
74 #endif
75 
76 #ifndef V_I1REF
77 #define V_I1REF(X) V_UNION(X, pcVal)
78 #endif
79 
80 #ifndef V_UI2REF
81 #define V_UI2REF(X) V_UNION(X, puiVal)
82 #endif
83 
84 #ifndef V_INT
85 #define V_INT(X) V_UNION(X, intVal)
86 #endif
87 
88 #ifndef V_INTREF
89 #define V_INTREF(X) V_UNION(X, pintVal)
90 #endif
91 
92 #ifndef V_UINT
93 #define V_UINT(X) V_UNION(X, uintVal)
94 #endif
95 
96 #ifndef V_UINTREF
97 #define V_UINTREF(X) V_UNION(X, puintVal)
98 #endif
99 
100 /*
101  * unfortunately IID_IMultiLanguage2 is not included in any libXXX.a
102  * in Cygwin(mingw32).
103  */
104 #if defined(__CYGWIN__) || defined(__MINGW32__)
105 #undef IID_IMultiLanguage2
106 const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}};
107 #endif
108 
109 #define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0
110 
111 #define OLE_ADDREF(X) (X) ? ((X)->lpVtbl->AddRef(X)) : 0
112 
113 #define OLE_GET_TYPEATTR(X, Y) ((X)->lpVtbl->GetTypeAttr((X), (Y)))
114 #define OLE_RELEASE_TYPEATTR(X, Y) ((X)->lpVtbl->ReleaseTypeAttr((X), (Y)))
115 
116 #define OLE_FREE(x) {\
117  if(g_ole_initialized == TRUE) {\
118  if(x) {\
119  OLE_RELEASE(x);\
120  (x) = 0;\
121  }\
122  }\
123 }
124 
125 #define OLEData_Get_Struct(obj, pole) {\
126  Data_Get_Struct(obj, struct oledata, pole);\
127  if(!pole->pDispatch) {\
128  rb_raise(rb_eRuntimeError, "failed to get Dispatch Interface");\
129  }\
130 }
131 
132 #ifdef HAVE_LONG_LONG
133 #define I8_2_NUM LL2NUM
134 #define UI8_2_NUM ULL2NUM
135 #define NUM2I8 NUM2LL
136 #define NUM2UI8 NUM2ULL
137 #else
138 #define I8_2_NUM INT2NUM
139 #define UI8_2_NUM UINT2NUM
140 #define NUM2I8 NUM2INT
141 #define NUM2UI8 NUM2UINT
142 #endif
143 
144 #define WC2VSTR(x) ole_wc2vstr((x), TRUE)
145 
146 #define WIN32OLE_VERSION "1.5.3"
147 
148 typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
149  (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
150 
151 typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile,
152  UINT uCommand, DWORD dwData);
153 typedef BOOL (FNENUMSYSEMCODEPAGES) (CODEPAGE_ENUMPROC, DWORD);
154 typedef struct {
157 
159 
161  STDMETHOD(QueryInterface)(
162  PEVENTSINK,
163  REFIID,
164  LPVOID *);
165  STDMETHOD_(ULONG, AddRef)(PEVENTSINK);
166  STDMETHOD_(ULONG, Release)(PEVENTSINK);
167 
168  STDMETHOD(GetTypeInfoCount)(
169  PEVENTSINK,
170  UINT *);
171  STDMETHOD(GetTypeInfo)(
172  PEVENTSINK,
173  UINT,
174  LCID,
175  ITypeInfo **);
176  STDMETHOD(GetIDsOfNames)(
177  PEVENTSINK,
178  REFIID,
179  OLECHAR **,
180  UINT,
181  LCID,
182  DISPID *);
183  STDMETHOD(Invoke)(
184  PEVENTSINK,
185  DISPID,
186  REFIID,
187  LCID,
188  WORD,
189  DISPPARAMS *,
190  VARIANT *,
191  EXCEPINFO *,
192  UINT *);
193 };
194 
195 typedef struct tagIEVENTSINKOBJ {
198  IID m_iid;
200  ITypeInfo *pTypeInfo;
202 
214 
216 static ID id_events;
217 static BOOL g_ole_initialized = FALSE;
218 static BOOL g_cp_installed = FALSE;
219 static BOOL g_lcid_installed = FALSE;
220 static HINSTANCE ghhctrl = NULL;
221 static HINSTANCE gole32 = NULL;
222 static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL;
224 static IDispatchVtbl com_vtbl;
225 static UINT cWIN32OLE_cp = CP_ACP;
226 static LCID cWIN32OLE_lcid = LOCALE_SYSTEM_DEFAULT;
228 static UINT g_cp_to_check = CP_ACP;
229 static char g_lcid_to_check[8 + 1];
230 static VARTYPE g_nil_to = VT_ERROR;
232 static IMessageFilterVtbl message_filter;
233 static IMessageFilter imessage_filter = { &message_filter };
234 static IMessageFilter* previous_filter;
235 
236 #if defined(HAVE_TYPE_IMULTILANGUAGE2)
237 static IMultiLanguage2 *pIMultiLanguage = NULL;
238 #elif defined(HAVE_TYPE_IMULTILANGUAGE)
239 static IMultiLanguage *pIMultiLanguage = NULL;
240 #else
241 #define pIMultiLanguage NULL /* dummy */
242 #endif
243 
244 struct oledata {
245  IDispatch *pDispatch;
246 };
247 
249  ITypeLib *pTypeLib;
250 };
251 
252 struct oletypedata {
253  ITypeInfo *pTypeInfo;
254 };
255 
257  ITypeInfo *pOwnerTypeInfo;
258  ITypeInfo *pTypeInfo;
259  UINT index;
260 };
261 
263  ITypeInfo *pTypeInfo;
264  UINT index;
265 };
266 
267 struct oleparamdata {
268  ITypeInfo *pTypeInfo;
270  UINT index;
271 };
272 
273 struct oleeventdata {
275  IConnectionPoint *pConnectionPoint;
276  long event_id;
277 };
278 
279 struct oleparam {
280  DISPPARAMS dp;
281  OLECHAR** pNamedArgs;
282 };
283 
285  VARIANT realvar;
286  VARIANT var;
287 };
288 
289 
290 static HRESULT ( STDMETHODCALLTYPE QueryInterface )(IDispatch __RPC_FAR *, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
291 static ULONG ( STDMETHODCALLTYPE AddRef )(IDispatch __RPC_FAR * This);
292 static ULONG ( STDMETHODCALLTYPE Release )(IDispatch __RPC_FAR * This);
293 static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(IDispatch __RPC_FAR * This, UINT __RPC_FAR *pctinfo);
294 static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(IDispatch __RPC_FAR * This, UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo);
295 static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(IDispatch __RPC_FAR * This, REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId);
296 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);
297 static IDispatch* val2dispatch(VALUE val);
298 static double rbtime2vtdate(VALUE tmobj);
299 static VALUE vtdate2rbtime(double date);
300 static rb_encoding *ole_cp2encoding(UINT cp);
301 static UINT ole_encoding2cp(rb_encoding *enc);
302 NORETURN(static void failed_load_conv51932(void));
303 #ifndef pIMultiLanguage
304 static void load_conv_function51932(void);
305 #endif
306 static UINT ole_init_cp(void);
307 static char *ole_wc2mb(LPWSTR pw);
308 static VALUE ole_hresult2msg(HRESULT hr);
309 static void ole_freeexceptinfo(EXCEPINFO *pExInfo);
310 static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo);
311 static void ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...);
312 static void ole_initialize();
313 static void ole_msg_loop();
314 static void ole_free(struct oledata *pole);
315 static void oletypelib_free(struct oletypelibdata *poletypelib);
316 static void oletype_free(struct oletypedata *poletype);
317 static void olemethod_free(struct olemethoddata *polemethod);
318 static void olevariable_free(struct olevariabledata *polevar);
319 static void oleparam_free(struct oleparamdata *pole);
320 static LPWSTR ole_vstr2wc(VALUE vstr);
321 static LPWSTR ole_mb2wc(char *pm, int len);
322 static VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree);
323 static VALUE ole_ary_m_entry(VALUE val, long *pid);
324 static void * get_ptr_of_variant(VARIANT *pvar);
325 static VALUE is_all_index_under(long *pid, long *pub, long dim);
326 static void ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vt);
327 static long dimension(VALUE val);
328 static long ary_len_of_dim(VALUE ary, long dim);
329 static HRESULT ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt);
330 static void ole_val2variant(VALUE val, VARIANT *var);
331 static void ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt);
332 static void ole_val2ptr_variant(VALUE val, VARIANT *var);
333 static void ole_set_byref(VARIANT *realvar, VARIANT *var, VARTYPE vt);
334 static void ole_val2olevariantdata(VALUE val, VARTYPE vt, struct olevariantdata *pvar);
335 static void ole_val2variant2(VALUE val, VARIANT *var);
336 static VALUE make_inspect(const char *class_name, VALUE detail);
337 static VALUE default_inspect(VALUE self, const char *class_name);
338 static VALUE ole_set_member(VALUE self, IDispatch *dispatch);
339 static VALUE fole_s_allocate(VALUE klass);
340 static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv);
341 static VALUE ary_new_dim(VALUE myary, long *pid, long *plb, long dim);
342 static void ary_store_dim(VALUE myary, long *pid, long *plb, long dim, VALUE val);
343 static VALUE ole_variant2val(VARIANT *pvar);
344 static LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey);
345 static LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey);
346 static VALUE reg_enum_key(HKEY hkey, DWORD i);
347 static VALUE reg_get_val(HKEY hkey, const char *subkey);
348 static VALUE reg_get_typelib_file_path(HKEY hkey);
351 static VALUE typelib_file(VALUE ole);
352 static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self);
353 static HRESULT clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid);
354 static VALUE ole_create_dcom(int argc, VALUE *argv, VALUE self);
355 static VALUE ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self);
356 static VALUE fole_s_connect(int argc, VALUE *argv, VALUE self);
357 static VALUE fole_s_const_load(int argc, VALUE *argv, VALUE self);
358 static VALUE ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes);
359 static ULONG reference_count(struct oledata * pole);
360 static VALUE fole_s_reference_count(VALUE self, VALUE obj);
361 static VALUE fole_s_free(VALUE self, VALUE obj);
362 static HWND ole_show_help(VALUE helpfile, VALUE helpcontext);
363 static VALUE fole_s_show_help(int argc, VALUE *argv, VALUE self);
364 static VALUE fole_s_get_code_page(VALUE self);
365 static BOOL CALLBACK installed_code_page_proc(LPTSTR str);
366 static BOOL code_page_installed(UINT cp);
367 static VALUE fole_s_set_code_page(VALUE self, VALUE vcp);
368 static VALUE fole_s_get_locale(VALUE self);
369 static BOOL CALLBACK installed_lcid_proc(LPTSTR str);
370 static BOOL lcid_installed(LCID lcid);
371 static VALUE fole_s_set_locale(VALUE self, VALUE vlcid);
372 static VALUE fole_s_create_guid(VALUE self);
373 static void ole_pure_initialize();
374 static VALUE fole_s_ole_initialize(VALUE self);
375 static void ole_pure_uninitialize();
376 static VALUE fole_s_ole_uninitialize(VALUE self);
377 static VALUE fole_initialize(int argc, VALUE *argv, VALUE self);
378 static VALUE hash2named_arg(VALUE pair, struct oleparam* pOp);
379 static VALUE set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end);
380 static VALUE ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket);
381 static VALUE fole_invoke(int argc, VALUE *argv, VALUE self);
382 static VALUE ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind);
383 static VALUE fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types);
384 static VALUE fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
385 static VALUE fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
387 static VALUE fole_setproperty(int argc, VALUE *argv, VALUE self);
389 static VALUE ole_propertyput(VALUE self, VALUE property, VALUE value);
390 static VALUE fole_free(VALUE self);
391 static VALUE ole_each_sub(VALUE pEnumV);
392 static VALUE ole_ienum_free(VALUE pEnumV);
393 static VALUE fole_each(VALUE self);
394 static VALUE fole_missing(int argc, VALUE *argv, VALUE self);
395 static VALUE ole_method_sub(VALUE self, ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE name);
396 static VALUE olemethod_from_typeinfo(VALUE self, ITypeInfo *pTypeInfo, VALUE name);
397 static VALUE ole_methods_sub(ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE methods, int mask);
398 static VALUE ole_methods_from_typeinfo(ITypeInfo *pTypeInfo, int mask);
399 static HRESULT typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti);
400 static VALUE ole_methods(VALUE self, int mask);
401 static VALUE fole_methods(VALUE self);
402 static VALUE fole_get_methods(VALUE self);
403 static VALUE fole_put_methods(VALUE self);
404 static VALUE fole_func_methods(VALUE self);
405 static VALUE ole_type_from_itypeinfo(ITypeInfo *pTypeInfo);
406 static VALUE fole_type(VALUE self);
407 static VALUE ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo);
408 static VALUE fole_typelib(VALUE self);
409 static VALUE fole_query_interface(VALUE self, VALUE str_iid);
410 static VALUE fole_respond_to(VALUE self, VALUE method);
411 static HRESULT ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile);
412 static VALUE ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
413 static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
414 static VALUE ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
415 static VALUE fole_method_help(VALUE self, VALUE cmdname);
416 static VALUE fole_activex_initialize(VALUE self);
417 static VALUE foletype_s_ole_classes(VALUE self, VALUE typelib);
418 static VALUE foletype_s_typelibs(VALUE self);
419 static VALUE foletype_s_progids(VALUE self);
420 static VALUE foletype_s_allocate(VALUE klass);
421 static VALUE oletype_set_member(VALUE self, ITypeInfo *pTypeInfo, VALUE name);
422 static VALUE oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass);
423 static VALUE oletypelib_set_member(VALUE self, ITypeLib *pTypeLib);
424 static ITypeLib * oletypelib_get_typelib(VALUE self);
425 static void oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr);
426 static VALUE foletypelib_s_typelibs(VALUE self);
429 static VALUE oletypelib_search_registry(VALUE self, VALUE typelib);
430 static VALUE foletypelib_s_allocate(VALUE klass);
432 static VALUE foletypelib_guid(VALUE self);
433 static VALUE foletypelib_name(VALUE self);
434 static VALUE foletypelib_version(VALUE self);
437 static VALUE oletypelib_path(VALUE guid, VALUE version);
438 static HRESULT oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib);
439 static VALUE foletypelib_path(VALUE self);
440 static VALUE foletypelib_visible(VALUE self);
442 static VALUE foletypelib_ole_types(VALUE self);
443 static VALUE foletypelib_inspect(VALUE self);
444 static VALUE foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass);
445 static VALUE foletype_name(VALUE self);
446 static VALUE ole_ole_type(ITypeInfo *pTypeInfo);
447 static VALUE foletype_ole_type(VALUE self);
448 static VALUE ole_type_guid(ITypeInfo *pTypeInfo);
449 static VALUE foletype_guid(VALUE self);
450 static VALUE ole_type_progid(ITypeInfo *pTypeInfo);
451 static VALUE foletype_progid(VALUE self);
452 static VALUE ole_type_visible(ITypeInfo *pTypeInfo);
453 static VALUE foletype_visible(VALUE self);
454 static VALUE ole_type_major_version(ITypeInfo *pTypeInfo);
455 static VALUE foletype_major_version(VALUE self);
456 static VALUE ole_type_minor_version(ITypeInfo *pTypeInfo);
457 static VALUE foletype_minor_version(VALUE self);
458 static VALUE ole_type_typekind(ITypeInfo *pTypeInfo);
459 static VALUE foletype_typekind(VALUE self);
460 static VALUE ole_type_helpstring(ITypeInfo *pTypeInfo);
461 static VALUE foletype_helpstring(VALUE self);
462 static VALUE ole_type_src_type(ITypeInfo *pTypeInfo);
463 static VALUE foletype_src_type(VALUE self);
464 static VALUE ole_type_helpfile(ITypeInfo *pTypeInfo);
465 static VALUE foletype_helpfile(VALUE self);
466 static VALUE ole_type_helpcontext(ITypeInfo *pTypeInfo);
467 static VALUE foletype_helpcontext(VALUE self);
468 static VALUE foletype_ole_typelib(VALUE self);
469 static VALUE ole_type_impl_ole_types(ITypeInfo *pTypeInfo, int implflags);
470 static VALUE foletype_impl_ole_types(VALUE self);
474 static VALUE foletype_inspect(VALUE self);
475 static VALUE ole_variables(ITypeInfo *pTypeInfo);
476 static VALUE foletype_variables(VALUE self);
477 static VALUE foletype_methods(VALUE self);
478 static VALUE folevariable_name(VALUE self);
479 static VALUE ole_variable_ole_type(ITypeInfo *pTypeInfo, UINT var_index);
480 static VALUE folevariable_ole_type(VALUE self);
481 static VALUE ole_variable_ole_type_detail(ITypeInfo *pTypeInfo, UINT var_index);
483 static VALUE ole_variable_value(ITypeInfo *pTypeInfo, UINT var_index);
484 static VALUE folevariable_value(VALUE self);
485 static VALUE ole_variable_visible(ITypeInfo *pTypeInfo, UINT var_index);
486 static VALUE folevariable_visible(VALUE self);
487 static VALUE ole_variable_kind(ITypeInfo *pTypeInfo, UINT var_index);
489 static VALUE ole_variable_varkind(ITypeInfo *pTypeInfo, UINT var_index);
490 static VALUE folevariable_varkind(VALUE self);
491 static VALUE folevariable_inspect(VALUE self);
492 static VALUE olemethod_set_member(VALUE self, ITypeInfo *pTypeInfo, ITypeInfo *pOwnerTypeInfo, int index, VALUE name);
493 static VALUE folemethod_s_allocate(VALUE klass);
494 static VALUE folemethod_initialize(VALUE self, VALUE oletype, VALUE method);
495 static VALUE folemethod_name(VALUE self);
496 static VALUE ole_method_return_type(ITypeInfo *pTypeInfo, UINT method_index);
497 static VALUE folemethod_return_type(VALUE self);
498 static VALUE ole_method_return_vtype(ITypeInfo *pTypeInfo, UINT method_index);
499 static VALUE folemethod_return_vtype(VALUE self);
500 static VALUE ole_method_return_type_detail(ITypeInfo *pTypeInfo, UINT method_index);
502 static VALUE ole_method_invkind(ITypeInfo *pTypeInfo, UINT method_index);
503 static VALUE ole_method_invoke_kind(ITypeInfo *pTypeInfo, UINT method_index);
504 static VALUE folemethod_invkind(VALUE self);
505 static VALUE folemethod_invoke_kind(VALUE self);
506 static VALUE ole_method_visible(ITypeInfo *pTypeInfo, UINT method_index);
507 static VALUE folemethod_visible(VALUE self);
508 static VALUE ole_method_event(ITypeInfo *pTypeInfo, UINT method_index, VALUE method_name);
509 static VALUE folemethod_event(VALUE self);
511 static VALUE ole_method_docinfo_from_type(ITypeInfo *pTypeInfo, UINT method_index, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile);
512 static VALUE ole_method_helpstring(ITypeInfo *pTypeInfo, UINT method_index);
513 static VALUE folemethod_helpstring(VALUE self);
514 static VALUE ole_method_helpfile(ITypeInfo *pTypeInfo, UINT method_index);
515 static VALUE folemethod_helpfile(VALUE self);
516 static VALUE ole_method_helpcontext(ITypeInfo *pTypeInfo, UINT method_index);
517 static VALUE folemethod_helpcontext(VALUE self);
518 static VALUE ole_method_dispid(ITypeInfo *pTypeInfo, UINT method_index);
519 static VALUE folemethod_dispid(VALUE self);
520 static VALUE ole_method_offset_vtbl(ITypeInfo *pTypeInfo, UINT method_index);
521 static VALUE folemethod_offset_vtbl(VALUE self);
522 static VALUE ole_method_size_params(ITypeInfo *pTypeInfo, UINT method_index);
523 static VALUE folemethod_size_params(VALUE self);
524 static VALUE ole_method_size_opt_params(ITypeInfo *pTypeInfo, UINT method_index);
526 static VALUE ole_method_params(ITypeInfo *pTypeInfo, UINT method_index);
527 static VALUE folemethod_params(VALUE self);
528 static VALUE folemethod_inspect(VALUE self);
529 static VALUE foleparam_s_allocate(VALUE klass);
530 static VALUE oleparam_ole_param_from_index(VALUE self, ITypeInfo *pTypeInfo, UINT method_index, int param_index);
531 static VALUE oleparam_ole_param(VALUE self, VALUE olemethod, int n);
532 static VALUE foleparam_initialize(VALUE self, VALUE olemethod, VALUE n);
533 static VALUE foleparam_name(VALUE self);
534 static VALUE ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index);
535 static VALUE foleparam_ole_type(VALUE self);
536 static VALUE ole_param_ole_type_detail(ITypeInfo *pTypeInfo, UINT method_index, UINT index);
538 static VALUE ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT mask);
539 static VALUE foleparam_input(VALUE self);
540 static VALUE foleparam_output(VALUE self);
541 static VALUE foleparam_optional(VALUE self);
542 static VALUE foleparam_retval(VALUE self);
543 static VALUE ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index);
544 static VALUE foleparam_default(VALUE self);
545 static VALUE foleparam_inspect(VALUE self);
546 static long ole_search_event_at(VALUE ary, VALUE ev);
547 static VALUE ole_search_event(VALUE ary, VALUE ev, BOOL *is_default);
548 static VALUE ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler);
549 static void ole_delete_event(VALUE ary, VALUE ev);
550 static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams);
551 static VALUE hash2result(VALUE hash);
552 static void ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams);
553 static VALUE exec_callback(VALUE arg);
555 static HRESULT find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo);
556 static HRESULT find_coclass(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **pTypeInfo2, TYPEATTR **pTypeAttr2);
557 static HRESULT find_default_source_from_typeinfo(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **ppTypeInfo);
558 static HRESULT find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo);
559 static void ole_event_free(struct oleeventdata *poleev);
560 static VALUE fev_s_allocate(VALUE klass);
561 static VALUE ev_advise(int argc, VALUE *argv, VALUE self);
562 static VALUE fev_initialize(int argc, VALUE *argv, VALUE self);
563 static VALUE fev_s_msg_loop(VALUE klass);
564 static void add_event_call_back(VALUE obj, VALUE event, VALUE data);
565 static VALUE ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg);
566 static VALUE fev_on_event(int argc, VALUE *argv, VALUE self);
567 static VALUE fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self);
568 static VALUE fev_off_event(int argc, VALUE *argv, VALUE self);
569 static VALUE fev_unadvise(VALUE self);
570 static VALUE fev_set_handler(VALUE self, VALUE val);
571 static VALUE fev_get_handler(VALUE self);
572 static VALUE evs_push(VALUE ev);
573 static VALUE evs_delete(long i);
574 static VALUE evs_entry(long i);
575 static VALUE evs_length();
576 static void olevariant_free(struct olevariantdata *pvar);
577 static VALUE folevariant_s_allocate(VALUE klass);
578 static VALUE folevariant_s_array(VALUE klass, VALUE dims, VALUE vvt);
580 static long *ary2safe_array_index(int ary_size, VALUE *ary, SAFEARRAY *psa);
581 static void unlock_safe_array(SAFEARRAY *psa);
582 static SAFEARRAY *get_locked_safe_array(VALUE val);
583 static VALUE folevariant_ary_aref(int argc, VALUE *argv, VALUE self);
584 static VOID * val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt);
585 static VALUE folevariant_ary_aset(int argc, VALUE *argv, VALUE self);
586 static VALUE folevariant_value(VALUE self);
587 static VALUE folevariant_vartype(VALUE self);
588 static VALUE folevariant_set_value(VALUE self, VALUE val);
589 static void init_enc2cp();
590 static void free_enc2cp();
591 
592 static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)(
593  IMessageFilter __RPC_FAR * This,
594  /* [in] */ REFIID riid,
595  /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
596 {
597  if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
598  || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0)
599  {
601  return S_OK;
602  }
603  return E_NOINTERFACE;
604 }
605 
606 static ULONG (STDMETHODCALLTYPE mf_AddRef)(
607  IMessageFilter __RPC_FAR * This)
608 {
609  return 1;
610 }
611 
612 static ULONG (STDMETHODCALLTYPE mf_Release)(
613  IMessageFilter __RPC_FAR * This)
614 {
615  return 1;
616 }
617 
618 static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)(
619  IMessageFilter __RPC_FAR * pThis,
620  DWORD dwCallType, //Type of incoming call
621  HTASK threadIDCaller, //Task handle calling this task
622  DWORD dwTickCount, //Elapsed tick count
623  LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure
624  )
625 {
626 #ifdef DEBUG_MESSAGEFILTER
627  printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount);
628  fflush(stdout);
629 #endif
630  switch (dwCallType)
631  {
632  case CALLTYPE_ASYNC:
633  case CALLTYPE_TOPLEVEL_CALLPENDING:
634  case CALLTYPE_ASYNC_CALLPENDING:
635  if (rb_during_gc()) {
636  return SERVERCALL_RETRYLATER;
637  }
638  break;
639  default:
640  break;
641  }
642  if (previous_filter) {
643  return previous_filter->lpVtbl->HandleInComingCall(previous_filter,
644  dwCallType,
645  threadIDCaller,
646  dwTickCount,
648  }
649  return SERVERCALL_ISHANDLED;
650 }
651 
652 static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)(
653  IMessageFilter* pThis,
654  HTASK threadIDCallee, //Server task handle
655  DWORD dwTickCount, //Elapsed tick count
656  DWORD dwRejectType //Returned rejection message
657  )
658 {
659  if (previous_filter) {
660  return previous_filter->lpVtbl->RetryRejectedCall(previous_filter,
661  threadIDCallee,
662  dwTickCount,
663  dwRejectType);
664  }
665  return 1000;
666 }
667 
668 static DWORD (STDMETHODCALLTYPE mf_MessagePending)(
669  IMessageFilter* pThis,
670  HTASK threadIDCallee, //Called applications task handle
671  DWORD dwTickCount, //Elapsed tick count
672  DWORD dwPendingType //Call type
673  )
674 {
675  if (rb_during_gc()) {
676  return PENDINGMSG_WAITNOPROCESS;
677  }
678  if (previous_filter) {
679  return previous_filter->lpVtbl->MessagePending(previous_filter,
680  threadIDCallee,
681  dwTickCount,
682  dwPendingType);
683  }
684  return PENDINGMSG_WAITNOPROCESS;
685 }
686 
687 typedef struct _Win32OLEIDispatch
688 {
689  IDispatch dispatch;
693 
694 static HRESULT ( STDMETHODCALLTYPE QueryInterface )(
695  IDispatch __RPC_FAR * This,
696  /* [in] */ REFIID riid,
697  /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
698 {
699  if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
700  || MEMCMP(riid, &IID_IDispatch, GUID, 1) == 0)
701  {
703  p->refcount++;
704  *ppvObject = This;
705  return S_OK;
706  }
707  return E_NOINTERFACE;
708 }
709 
710 static ULONG ( STDMETHODCALLTYPE AddRef )(
711  IDispatch __RPC_FAR * This)
712 {
714  return ++(p->refcount);
715 }
716 
717 static ULONG ( STDMETHODCALLTYPE Release )(
718  IDispatch __RPC_FAR * This)
719 {
721  ULONG u = --(p->refcount);
722  if (u == 0) {
723  st_data_t key = p->obj;
724  st_delete(DATA_PTR(com_hash), &key, 0);
725  free(p);
726  }
727  return u;
728 }
729 
730 static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(
731  IDispatch __RPC_FAR * This,
732  /* [out] */ UINT __RPC_FAR *pctinfo)
733 {
734  return E_NOTIMPL;
735 }
736 
737 static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(
738  IDispatch __RPC_FAR * This,
739  /* [in] */ UINT iTInfo,
740  /* [in] */ LCID lcid,
741  /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
742 {
743  return E_NOTIMPL;
744 }
745 
746 
747 static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(
748  IDispatch __RPC_FAR * This,
749  /* [in] */ REFIID riid,
750  /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
751  /* [in] */ UINT cNames,
752  /* [in] */ LCID lcid,
753  /* [size_is][out] */ DISPID __RPC_FAR *rgDispId)
754 {
755  /*
756  Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
757  */
758  char* psz = ole_wc2mb(*rgszNames); // support only one method
759  *rgDispId = rb_intern(psz);
760  free(psz);
761  return S_OK;
762 }
763 
764 static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )(
765  IDispatch __RPC_FAR * This,
766  /* [in] */ DISPID dispIdMember,
767  /* [in] */ REFIID riid,
768  /* [in] */ LCID lcid,
769  /* [in] */ WORD wFlags,
770  /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
771  /* [out] */ VARIANT __RPC_FAR *pVarResult,
772  /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
773  /* [out] */ UINT __RPC_FAR *puArgErr)
774 {
775  VALUE v;
776  int i;
777  int args = pDispParams->cArgs;
780  for (i = 0; i < args; i++) {
781  *(parg + i) = ole_variant2val(&pDispParams->rgvarg[args - i - 1]);
782  }
783  if (dispIdMember == DISPID_VALUE) {
784  if (wFlags == DISPATCH_METHOD) {
785  dispIdMember = rb_intern("call");
786  } else if (wFlags & DISPATCH_PROPERTYGET) {
787  dispIdMember = rb_intern("value");
788  }
789  }
790  v = rb_funcall2(p->obj, dispIdMember, args, parg);
791  ole_val2variant(v, pVarResult);
792  return S_OK;
793 }
794 
795 static IDispatch*
797 {
798  struct st_table *tbl = DATA_PTR(com_hash);
799  Win32OLEIDispatch* pdisp;
800  st_data_t data;
801 
802  if (st_lookup(tbl, val, &data)) {
803  pdisp = (Win32OLEIDispatch *)(data & ~FIXNUM_FLAG);
804  pdisp->refcount++;
805  }
806  else {
807  pdisp = ALLOC(Win32OLEIDispatch);
808  pdisp->dispatch.lpVtbl = &com_vtbl;
809  pdisp->refcount = 1;
810  pdisp->obj = val;
811  st_insert(tbl, val, (VALUE)pdisp | FIXNUM_FLAG);
812  }
813  return &pdisp->dispatch;
814 }
815 
816 static double
818 {
819  SYSTEMTIME st;
820  double t = 0;
821  memset(&st, 0, sizeof(SYSTEMTIME));
822  st.wYear = FIX2INT(rb_funcall(tmobj, rb_intern("year"), 0));
823  st.wMonth = FIX2INT(rb_funcall(tmobj, rb_intern("month"), 0));
824  st.wDay = FIX2INT(rb_funcall(tmobj, rb_intern("mday"), 0));
825  st.wHour = FIX2INT(rb_funcall(tmobj, rb_intern("hour"), 0));
826  st.wMinute = FIX2INT(rb_funcall(tmobj, rb_intern("min"), 0));
827  st.wSecond = FIX2INT(rb_funcall(tmobj, rb_intern("sec"), 0));
828  st.wMilliseconds = FIX2INT(rb_funcall(tmobj, rb_intern("nsec"), 0)) / 1000000;
829  SystemTimeToVariantTime(&st, &t);
830  return t;
831 }
832 
833 static VALUE
834 vtdate2rbtime(double date)
835 {
836  SYSTEMTIME st;
837  VALUE v;
838  VariantTimeToSystemTime(date, &st);
839 
840  v = rb_funcall(rb_cTime, rb_intern("new"), 6,
841  INT2FIX(st.wYear),
842  INT2FIX(st.wMonth),
843  INT2FIX(st.wDay),
844  INT2FIX(st.wHour),
845  INT2FIX(st.wMinute),
846  INT2FIX(st.wSecond));
847  if (st.wMilliseconds > 0) {
848  return rb_funcall(v, rb_intern("+"), 1, rb_float_new((double)(st.wMilliseconds / 1000.0)));
849  }
850  return v;
851 }
852 
853 #define ENC_MACHING_CP(enc,encname,cp) if(strcasecmp(rb_enc_name((enc)),(encname)) == 0) return cp
854 
855 static UINT ole_encoding2cp(rb_encoding *enc)
856 {
857  /*
858  * Is there any better solution to convert
859  * Ruby encoding to Windows codepage???
860  */
861  ENC_MACHING_CP(enc, "Big5", 950);
862  ENC_MACHING_CP(enc, "CP51932", 51932);
863  ENC_MACHING_CP(enc, "CP850", 850);
864  ENC_MACHING_CP(enc, "CP852", 852);
865  ENC_MACHING_CP(enc, "CP855", 855);
866  ENC_MACHING_CP(enc, "CP949", 949);
867  ENC_MACHING_CP(enc, "EUC-JP", 20932);
868  ENC_MACHING_CP(enc, "EUC-KR", 51949);
869  ENC_MACHING_CP(enc, "EUC-TW", 51950);
870  ENC_MACHING_CP(enc, "GB18030", 54936);
871  ENC_MACHING_CP(enc, "GB2312", 20936);
872  ENC_MACHING_CP(enc, "GBK", 936);
873  ENC_MACHING_CP(enc, "IBM437", 437);
874  ENC_MACHING_CP(enc, "IBM737", 737);
875  ENC_MACHING_CP(enc, "IBM775", 775);
876  ENC_MACHING_CP(enc, "IBM852", 852);
877  ENC_MACHING_CP(enc, "IBM855", 855);
878  ENC_MACHING_CP(enc, "IBM857", 857);
879  ENC_MACHING_CP(enc, "IBM860", 860);
880  ENC_MACHING_CP(enc, "IBM861", 861);
881  ENC_MACHING_CP(enc, "IBM862", 862);
882  ENC_MACHING_CP(enc, "IBM863", 863);
883  ENC_MACHING_CP(enc, "IBM864", 864);
884  ENC_MACHING_CP(enc, "IBM865", 865);
885  ENC_MACHING_CP(enc, "IBM866", 866);
886  ENC_MACHING_CP(enc, "IBM869", 869);
887  ENC_MACHING_CP(enc, "ISO-2022-JP", 50220);
888  ENC_MACHING_CP(enc, "ISO-8859-1", 28591);
889  ENC_MACHING_CP(enc, "ISO-8859-15", 28605);
890  ENC_MACHING_CP(enc, "ISO-8859-2", 28592);
891  ENC_MACHING_CP(enc, "ISO-8859-3", 28593);
892  ENC_MACHING_CP(enc, "ISO-8859-4", 28594);
893  ENC_MACHING_CP(enc, "ISO-8859-5", 28595);
894  ENC_MACHING_CP(enc, "ISO-8859-6", 28596);
895  ENC_MACHING_CP(enc, "ISO-8859-7", 28597);
896  ENC_MACHING_CP(enc, "ISO-8859-8", 28598);
897  ENC_MACHING_CP(enc, "ISO-8859-9", 28599);
898  ENC_MACHING_CP(enc, "KOI8-R", 20866);
899  ENC_MACHING_CP(enc, "KOI8-U", 21866);
900  ENC_MACHING_CP(enc, "Shift_JIS", 932);
901  ENC_MACHING_CP(enc, "UTF-16BE", 1201);
902  ENC_MACHING_CP(enc, "UTF-16LE", 1200);
903  ENC_MACHING_CP(enc, "UTF-7", 65000);
904  ENC_MACHING_CP(enc, "UTF-8", 65001);
905  ENC_MACHING_CP(enc, "Windows-1250", 1250);
906  ENC_MACHING_CP(enc, "Windows-1251", 1251);
907  ENC_MACHING_CP(enc, "Windows-1252", 1252);
908  ENC_MACHING_CP(enc, "Windows-1253", 1253);
909  ENC_MACHING_CP(enc, "Windows-1254", 1254);
910  ENC_MACHING_CP(enc, "Windows-1255", 1255);
911  ENC_MACHING_CP(enc, "Windows-1256", 1256);
912  ENC_MACHING_CP(enc, "Windows-1257", 1257);
913  ENC_MACHING_CP(enc, "Windows-1258", 1258);
914  ENC_MACHING_CP(enc, "Windows-31J", 932);
915  ENC_MACHING_CP(enc, "Windows-874", 874);
916  ENC_MACHING_CP(enc, "eucJP-ms", 20932);
917  return CP_ACP;
918 }
919 
920 static void
922 {
923  rb_raise(eWIN32OLERuntimeError, "fail to load convert function for CP51932");
924 }
925 
926 #ifndef pIMultiLanguage
927 static void
929 {
930  HRESULT hr = E_NOINTERFACE;
931  void *p;
932  if (!pIMultiLanguage) {
933 #if defined(HAVE_TYPE_IMULTILANGUAGE2)
934  hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
935  &IID_IMultiLanguage2, &p);
936 #elif defined(HAVE_TYPE_IMULTILANGUAGE)
937  hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
938  &IID_IMultiLanguage, &p);
939 #endif
940  if (FAILED(hr)) {
942  }
943  pIMultiLanguage = p;
944  }
945 }
946 #else
947 #define load_conv_function51932() failed_load_conv51932()
948 #endif
949 
950 #define conv_51932(cp) ((cp) == 51932 && (load_conv_function51932(), 1))
951 
952 static void
954 {
955  if (code_page_installed(cp)) {
956  cWIN32OLE_cp = cp;
957  } else {
958  switch(cp) {
959  case CP_ACP:
960  case CP_OEMCP:
961  case CP_MACCP:
962  case CP_THREAD_ACP:
963  case CP_SYMBOL:
964  case CP_UTF7:
965  case CP_UTF8:
966  cWIN32OLE_cp = cp;
967  break;
968  case 51932:
969  cWIN32OLE_cp = cp;
971  break;
972  default:
973  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.");
974  break;
975  }
976  }
977  cWIN32OLE_enc = ole_cp2encoding(cWIN32OLE_cp);
978 }
979 
980 
981 static UINT
983 {
984  UINT cp;
985  rb_encoding *encdef;
986  encdef = rb_default_internal_encoding();
987  if (!encdef) {
988  encdef = rb_default_external_encoding();
989  }
990  cp = ole_encoding2cp(encdef);
991  set_ole_codepage(cp);
992  return cp;
993 }
994 
995 struct myCPINFOEX {
997  BYTE DefaultChar[2];
998  BYTE LeadByte[12];
1000  UINT CodePage;
1001  char CodePageName[MAX_PATH];
1002 };
1003 
1004 static rb_encoding *
1006 {
1007  static BOOL (*pGetCPInfoEx)(UINT, DWORD, struct myCPINFOEX *) = NULL;
1008  struct myCPINFOEX* buf;
1009  VALUE enc_name;
1010  char *enc_cstr;
1011  int idx;
1012 
1013  if (!code_page_installed(cp)) {
1014  switch(cp) {
1015  case CP_ACP:
1016  cp = GetACP();
1017  break;
1018  case CP_OEMCP:
1019  cp = GetOEMCP();
1020  break;
1021  case CP_MACCP:
1022  case CP_THREAD_ACP:
1023  if (!pGetCPInfoEx) {
1024  pGetCPInfoEx = (BOOL (*)(UINT, DWORD, struct myCPINFOEX *))
1025  GetProcAddress(GetModuleHandle("kernel32"), "GetCPInfoEx");
1026  if (!pGetCPInfoEx) {
1027  pGetCPInfoEx = (void*)-1;
1028  }
1029  }
1030  buf = ALLOCA_N(struct myCPINFOEX, 1);
1031  ZeroMemory(buf, sizeof(struct myCPINFOEX));
1032  if (pGetCPInfoEx == (void*)-1 || !pGetCPInfoEx(cp, 0, buf)) {
1033  rb_raise(eWIN32OLERuntimeError, "cannot map codepage to encoding.");
1034  break; /* never reach here */
1035  }
1036  cp = buf->CodePage;
1037  break;
1038  case CP_SYMBOL:
1039  case CP_UTF7:
1040  case CP_UTF8:
1041  break;
1042  case 51932:
1044  break;
1045  default:
1046  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.");
1047  break;
1048  }
1049  }
1050 
1051  enc_name = rb_sprintf("CP%d", cp);
1052  idx = rb_enc_find_index(enc_cstr = StringValueCStr(enc_name));
1053  if (idx < 0)
1054  idx = rb_define_dummy_encoding(enc_cstr);
1055  return rb_enc_from_index(idx);
1056 }
1057 
1058 static char *
1059 ole_wc2mb(LPWSTR pw)
1060 {
1061  LPSTR pm;
1062  UINT size = 0;
1063  if (conv_51932(cWIN32OLE_cp)) {
1064 #ifndef pIMultiLanguage
1065  DWORD dw = 0;
1066  HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage,
1067  &dw, cWIN32OLE_cp, pw, NULL, NULL, &size);
1068  if (FAILED(hr)) {
1069  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp);
1070  }
1071  pm = ALLOC_N(char, size + 1);
1072  hr = pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage,
1073  &dw, cWIN32OLE_cp, pw, NULL, pm, &size);
1074  if (FAILED(hr)) {
1075  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp);
1076  }
1077  pm[size] = '\0';
1078 #endif
1079  return pm;
1080  }
1081  size = WideCharToMultiByte(cWIN32OLE_cp, 0, pw, -1, NULL, 0, NULL, NULL);
1082  if (size) {
1083  pm = ALLOC_N(char, size + 1);
1084  WideCharToMultiByte(cWIN32OLE_cp, 0, pw, -1, pm, size, NULL, NULL);
1085  pm[size] = '\0';
1086  }
1087  else {
1088  pm = ALLOC_N(char, 1);
1089  *pm = '\0';
1090  }
1091  return pm;
1092 }
1093 
1094 static VALUE
1096 {
1097  VALUE msg = Qnil;
1098  char *p_msg = NULL;
1099  char *term = NULL;
1100  DWORD dwCount;
1101 
1102  char strhr[100];
1103  sprintf(strhr, " HRESULT error code:0x%08x\n ", (unsigned)hr);
1104  msg = rb_str_new2(strhr);
1105  dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1106  FORMAT_MESSAGE_FROM_SYSTEM |
1107  FORMAT_MESSAGE_IGNORE_INSERTS,
1108  NULL, hr,
1109  MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
1110  (LPTSTR)&p_msg, 0, NULL);
1111  if (dwCount == 0) {
1112  dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1113  FORMAT_MESSAGE_FROM_SYSTEM |
1114  FORMAT_MESSAGE_IGNORE_INSERTS,
1115  NULL, hr, cWIN32OLE_lcid,
1116  (LPTSTR)&p_msg, 0, NULL);
1117  }
1118  if (dwCount > 0) {
1119  term = p_msg + strlen(p_msg);
1120  while (p_msg < term) {
1121  term--;
1122  if (*term == '\r' || *term == '\n')
1123  *term = '\0';
1124  else break;
1125  }
1126  if (p_msg[0] != '\0') {
1127  rb_str_cat2(msg, p_msg);
1128  }
1129  }
1130  LocalFree(p_msg);
1131  return msg;
1132 }
1133 
1134 static void
1135 ole_freeexceptinfo(EXCEPINFO *pExInfo)
1136 {
1137  SysFreeString(pExInfo->bstrDescription);
1138  SysFreeString(pExInfo->bstrSource);
1139  SysFreeString(pExInfo->bstrHelpFile);
1140 }
1141 
1142 static VALUE
1143 ole_excepinfo2msg(EXCEPINFO *pExInfo)
1144 {
1145  char error_code[40];
1146  char *pSource = NULL;
1147  char *pDescription = NULL;
1148  VALUE error_msg;
1149  if(pExInfo->pfnDeferredFillIn != NULL) {
1150  (*pExInfo->pfnDeferredFillIn)(pExInfo);
1151  }
1152  if (pExInfo->bstrSource != NULL) {
1153  pSource = ole_wc2mb(pExInfo->bstrSource);
1154  }
1155  if (pExInfo->bstrDescription != NULL) {
1156  pDescription = ole_wc2mb(pExInfo->bstrDescription);
1157  }
1158  if(pExInfo->wCode == 0) {
1159  sprintf(error_code, "\n OLE error code:%lX in ", pExInfo->scode);
1160  }
1161  else{
1162  sprintf(error_code, "\n OLE error code:%u in ", pExInfo->wCode);
1163  }
1164  error_msg = rb_str_new2(error_code);
1165  if(pSource != NULL) {
1166  rb_str_cat(error_msg, pSource, strlen(pSource));
1167  }
1168  else {
1169  rb_str_cat(error_msg, "<Unknown>", 9);
1170  }
1171  rb_str_cat2(error_msg, "\n ");
1172  if(pDescription != NULL) {
1173  rb_str_cat2(error_msg, pDescription);
1174  }
1175  else {
1176  rb_str_cat2(error_msg, "<No Description>");
1177  }
1178  if(pSource) free(pSource);
1179  if(pDescription) free(pDescription);
1180  ole_freeexceptinfo(pExInfo);
1181  return error_msg;
1182 }
1183 
1184 static void
1185 ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...)
1186 {
1187  va_list args;
1188  char buf[BUFSIZ];
1189  VALUE err_msg;
1190  va_init_list(args, fmt);
1191  vsnprintf(buf, BUFSIZ, fmt, args);
1192  va_end(args);
1193 
1194  err_msg = ole_hresult2msg(hr);
1195  if(err_msg != Qnil) {
1196  rb_raise(ecs, "%s\n%s", buf, StringValuePtr(err_msg));
1197  }
1198  else {
1199  rb_raise(ecs, "%s", buf);
1200  }
1201 }
1202 
1203 void
1205 {
1206  OleUninitialize();
1208 }
1209 
1210 static void
1212 {
1213  HRESULT hr;
1214 
1215  if(g_ole_initialized == FALSE) {
1216  hr = OleInitialize(NULL);
1217  if(FAILED(hr)) {
1218  ole_raise(hr, rb_eRuntimeError, "fail: OLE initialize");
1219  }
1221  /*
1222  * In some situation, OleUninitialize does not work fine. ;-<
1223  */
1224  /*
1225  atexit((void (*)(void))ole_uninitialize);
1226  */
1227  hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter);
1228  if(FAILED(hr)) {
1230  ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter");
1231  }
1232  }
1233 }
1234 
1235 static void
1237  MSG msg;
1238  while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
1239  TranslateMessage(&msg);
1240  DispatchMessage(&msg);
1241  }
1242 }
1243 
1244 static void
1245 ole_free(struct oledata *pole)
1246 {
1247  OLE_FREE(pole->pDispatch);
1248  free(pole);
1249 }
1250 
1251 static void
1252 oletypelib_free(struct oletypelibdata *poletypelib)
1253 {
1254  OLE_FREE(poletypelib->pTypeLib);
1255  free(poletypelib);
1256 }
1257 
1258 static void
1259 oletype_free(struct oletypedata *poletype)
1260 {
1261  OLE_FREE(poletype->pTypeInfo);
1262  free(poletype);
1263 }
1264 
1265 static void
1266 olemethod_free(struct olemethoddata *polemethod)
1267 {
1268  OLE_FREE(polemethod->pTypeInfo);
1269  OLE_FREE(polemethod->pOwnerTypeInfo);
1270  free(polemethod);
1271 }
1272 
1273 static void
1275 {
1276  OLE_FREE(polevar->pTypeInfo);
1277  free(polevar);
1278 }
1279 
1280 static void
1282 {
1283  OLE_FREE(pole->pTypeInfo);
1284  free(pole);
1285 }
1286 
1287 
1288 static LPWSTR
1290 {
1291  rb_encoding *enc;
1292  int cp;
1293  UINT size = 0;
1294  LPWSTR pw;
1295  st_data_t data;
1296  enc = rb_enc_get(vstr);
1297 
1298  if (st_lookup(enc2cp_table, (st_data_t)enc, &data)) {
1299  cp = data;
1300  } else {
1301  cp = ole_encoding2cp(enc);
1302  if (code_page_installed(cp) ||
1303  cp == CP_ACP ||
1304  cp == CP_OEMCP ||
1305  cp == CP_MACCP ||
1306  cp == CP_THREAD_ACP ||
1307  cp == CP_SYMBOL ||
1308  cp == CP_UTF7 ||
1309  cp == CP_UTF8 ||
1310  cp == 51932) {
1311  st_insert(enc2cp_table, (st_data_t)enc, (st_data_t)cp);
1312  } else {
1313  rb_raise(eWIN32OLERuntimeError, "not installed Windows codepage(%d) according to `%s'", cp, rb_enc_name(enc));
1314  }
1315  }
1316  if (conv_51932(cp)) {
1317 #ifndef pIMultiLanguage
1318  DWORD dw = 0;
1319  UINT len = RSTRING_LENINT(vstr);
1320  HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
1321  &dw, cp, RSTRING_PTR(vstr), &len, NULL, &size);
1322  if (FAILED(hr)) {
1323  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
1324  }
1325  pw = SysAllocStringLen(NULL, size);
1326  len = RSTRING_LEN(vstr);
1327  hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
1328  &dw, cp, RSTRING_PTR(vstr), &len, pw, &size);
1329  if (FAILED(hr)) {
1330  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
1331  }
1332 #endif
1333  return pw;
1334  }
1335  size = MultiByteToWideChar(cp, 0, RSTRING_PTR(vstr), RSTRING_LEN(vstr), NULL, 0);
1336  pw = SysAllocStringLen(NULL, size);
1337  MultiByteToWideChar(cp, 0, RSTRING_PTR(vstr), RSTRING_LEN(vstr), pw, size);
1338  return pw;
1339 }
1340 
1341 static LPWSTR
1342 ole_mb2wc(char *pm, int len)
1343 {
1344  UINT size = 0;
1345  LPWSTR pw;
1346 
1347  if (conv_51932(cWIN32OLE_cp)) {
1348 #ifndef pIMultiLanguage
1349  DWORD dw = 0;
1350  UINT n = len;
1351  HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
1352  &dw, cWIN32OLE_cp, pm, &n, NULL, &size);
1353  if (FAILED(hr)) {
1354  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cWIN32OLE_cp);
1355  }
1356  pw = SysAllocStringLen(NULL, size);
1357  hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
1358  &dw, cWIN32OLE_cp, pm, &n, pw, &size);
1359  if (FAILED(hr)) {
1360  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cWIN32OLE_cp);
1361  }
1362 #endif
1363  return pw;
1364  }
1365  size = MultiByteToWideChar(cWIN32OLE_cp, 0, pm, len, NULL, 0);
1366  pw = SysAllocStringLen(NULL, size - 1);
1367  MultiByteToWideChar(cWIN32OLE_cp, 0, pm, len, pw, size);
1368  return pw;
1369 }
1370 
1371 static VALUE
1372 ole_wc2vstr(LPWSTR pw, BOOL isfree)
1373 {
1374  char *p = ole_wc2mb(pw);
1375  VALUE vstr = rb_enc_str_new(p, strlen(p), cWIN32OLE_enc);
1376  if(isfree)
1377  SysFreeString(pw);
1378  free(p);
1379  return vstr;
1380 }
1381 
1382 static VALUE
1383 ole_ary_m_entry(VALUE val, long *pid)
1384 {
1385  VALUE obj = Qnil;
1386  int i = 0;
1387  obj = val;
1388  while(TYPE(obj) == T_ARRAY) {
1389  obj = rb_ary_entry(obj, pid[i]);
1390  i++;
1391  }
1392  return obj;
1393 }
1394 
1395 static void *
1396 get_ptr_of_variant(VARIANT *pvar)
1397 {
1398  switch(V_VT(pvar)) {
1399  case VT_UI1:
1400  return &V_UI1(pvar);
1401  break;
1402  case VT_I2:
1403  return &V_I2(pvar);
1404  break;
1405  case VT_UI2:
1406  return &V_UI2(pvar);
1407  break;
1408  case VT_I4:
1409  return &V_I4(pvar);
1410  break;
1411  case VT_UI4:
1412  return &V_UI4(pvar);
1413  break;
1414  case VT_R4:
1415  return &V_R4(pvar);
1416  break;
1417  case VT_R8:
1418  return &V_R8(pvar);
1419  break;
1420 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1421  case VT_I8:
1422  return &V_I8(pvar);
1423  break;
1424  case VT_UI8:
1425  return &V_UI8(pvar);
1426  break;
1427 #endif
1428  case VT_INT:
1429  return &V_INT(pvar);
1430  break;
1431  case VT_UINT:
1432  return &V_UINT(pvar);
1433  break;
1434  case VT_CY:
1435  return &V_CY(pvar);
1436  break;
1437  case VT_DATE:
1438  return &V_DATE(pvar);
1439  break;
1440  case VT_BSTR:
1441  return V_BSTR(pvar);
1442  break;
1443  case VT_DISPATCH:
1444  return V_DISPATCH(pvar);
1445  break;
1446  case VT_ERROR:
1447  return &V_ERROR(pvar);
1448  break;
1449  case VT_BOOL:
1450  return &V_BOOL(pvar);
1451  break;
1452  case VT_UNKNOWN:
1453  return V_UNKNOWN(pvar);
1454  break;
1455  case VT_ARRAY:
1456  return &V_ARRAY(pvar);
1457  break;
1458  default:
1459  return NULL;
1460  break;
1461  }
1462 }
1463 
1464 static VALUE
1465 is_all_index_under(long *pid, long *pub, long dim)
1466 {
1467  long i = 0;
1468  for (i = 0; i < dim; i++) {
1469  if (pid[i] > pub[i]) {
1470  return Qfalse;
1471  }
1472  }
1473  return Qtrue;
1474 }
1475 
1476 static void
1477 ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vt)
1478 {
1479  VALUE val1;
1480  HRESULT hr = S_OK;
1481  VARIANT var;
1482  VOID *p = NULL;
1483  long i = n;
1484  while(i >= 0) {
1485  val1 = ole_ary_m_entry(val, pid);
1486  VariantInit(&var);
1487  p = val2variant_ptr(val1, &var, vt);
1488  if (is_all_index_under(pid, pub, dim) == Qtrue) {
1489  if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
1490  (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
1491  rb_raise(eWIN32OLERuntimeError, "element of array does not have IDispatch or IUnknown Interface");
1492  }
1493  hr = SafeArrayPutElement(psa, pid, p);
1494  }
1495  if (FAILED(hr)) {
1496  ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement");
1497  }
1498  pid[i] += 1;
1499  if (pid[i] > pub[i]) {
1500  pid[i] = 0;
1501  i -= 1;
1502  } else {
1503  i = dim - 1;
1504  }
1505  }
1506 }
1507 
1508 static long
1510  long dim = 0;
1511  long dim1 = 0;
1512  long len = 0;
1513  long i = 0;
1514  if (TYPE(val) == T_ARRAY) {
1515  len = RARRAY_LEN(val);
1516  for (i = 0; i < len; i++) {
1517  dim1 = dimension(rb_ary_entry(val, i));
1518  if (dim < dim1) {
1519  dim = dim1;
1520  }
1521  }
1522  dim += 1;
1523  }
1524  return dim;
1525 }
1526 
1527 static long
1528 ary_len_of_dim(VALUE ary, long dim) {
1529  long ary_len = 0;
1530  long ary_len1 = 0;
1531  long len = 0;
1532  long i = 0;
1533  VALUE val;
1534  if (dim == 0) {
1535  if (TYPE(ary) == T_ARRAY) {
1536  ary_len = RARRAY_LEN(ary);
1537  }
1538  } else {
1539  if (TYPE(ary) == T_ARRAY) {
1540  len = RARRAY_LEN(ary);
1541  for (i = 0; i < len; i++) {
1542  val = rb_ary_entry(ary, i);
1543  ary_len1 = ary_len_of_dim(val, dim-1);
1544  if (ary_len < ary_len1) {
1545  ary_len = ary_len1;
1546  }
1547  }
1548  }
1549  }
1550  return ary_len;
1551 }
1552 
1553 static HRESULT
1554 ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt)
1555 {
1556  long dim = 0;
1557  int i = 0;
1558  HRESULT hr = S_OK;
1559 
1560  SAFEARRAYBOUND *psab = NULL;
1561  SAFEARRAY *psa = NULL;
1562  long *pub, *pid;
1563 
1564  Check_Type(val, T_ARRAY);
1565 
1566  dim = dimension(val);
1567 
1568  psab = ALLOC_N(SAFEARRAYBOUND, dim);
1569  pub = ALLOC_N(long, dim);
1570  pid = ALLOC_N(long, dim);
1571 
1572  if(!psab || !pub || !pid) {
1573  if(pub) free(pub);
1574  if(psab) free(psab);
1575  if(pid) free(pid);
1576  rb_raise(rb_eRuntimeError, "memory allocation error");
1577  }
1578 
1579  for (i = 0; i < dim; i++) {
1580  psab[i].cElements = ary_len_of_dim(val, i);
1581  psab[i].lLbound = 0;
1582  pub[i] = psab[i].cElements - 1;
1583  pid[i] = 0;
1584  }
1585  /* Create and fill VARIANT array */
1586  if ((vt & ~VT_BYREF) == VT_ARRAY) {
1587  vt = (vt | VT_VARIANT);
1588  }
1589  psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
1590  if (psa == NULL)
1591  hr = E_OUTOFMEMORY;
1592  else
1593  hr = SafeArrayLock(psa);
1594  if (SUCCEEDED(hr)) {
1595  ole_set_safe_array(dim-1, psa, pid, pub, val, dim, (VARTYPE)(vt & VT_TYPEMASK));
1596  hr = SafeArrayUnlock(psa);
1597  }
1598 
1599  if(pub) free(pub);
1600  if(psab) free(psab);
1601  if(pid) free(pid);
1602 
1603  if (SUCCEEDED(hr)) {
1604  V_VT(var) = vt;
1605  V_ARRAY(var) = psa;
1606  }
1607  else {
1608  if (psa != NULL)
1609  SafeArrayDestroy(psa);
1610  }
1611  return hr;
1612 }
1613 
1614 static void
1615 ole_val2variant(VALUE val, VARIANT *var)
1616 {
1617  struct oledata *pole;
1618  struct olevariantdata *pvar;
1619  if(rb_obj_is_kind_of(val, cWIN32OLE)) {
1620  Data_Get_Struct(val, struct oledata, pole);
1621  OLE_ADDREF(pole->pDispatch);
1622  V_VT(var) = VT_DISPATCH;
1623  V_DISPATCH(var) = pole->pDispatch;
1624  return;
1625  }
1627  Data_Get_Struct(val, struct olevariantdata, pvar);
1628  VariantCopy(var, &(pvar->var));
1629  return;
1630  }
1631 
1632  if (rb_obj_is_kind_of(val, rb_cTime)) {
1633  V_VT(var) = VT_DATE;
1634  V_DATE(var) = rbtime2vtdate(val);
1635  return;
1636  }
1637  switch (TYPE(val)) {
1638  case T_ARRAY:
1639  ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY);
1640  break;
1641  case T_STRING:
1642  V_VT(var) = VT_BSTR;
1643  V_BSTR(var) = ole_vstr2wc(val);
1644  break;
1645  case T_FIXNUM:
1646  V_VT(var) = VT_I4;
1647  V_I4(var) = NUM2INT(val);
1648  break;
1649  case T_BIGNUM:
1650  V_VT(var) = VT_R8;
1651  V_R8(var) = rb_big2dbl(val);
1652  break;
1653  case T_FLOAT:
1654  V_VT(var) = VT_R8;
1655  V_R8(var) = NUM2DBL(val);
1656  break;
1657  case T_TRUE:
1658  V_VT(var) = VT_BOOL;
1659  V_BOOL(var) = VARIANT_TRUE;
1660  break;
1661  case T_FALSE:
1662  V_VT(var) = VT_BOOL;
1663  V_BOOL(var) = VARIANT_FALSE;
1664  break;
1665  case T_NIL:
1666  if (g_nil_to == VT_ERROR) {
1667  V_VT(var) = VT_ERROR;
1668  V_ERROR(var) = DISP_E_PARAMNOTFOUND;
1669  }else {
1670  V_VT(var) = VT_EMPTY;
1671  }
1672  break;
1673  default:
1674  V_VT(var) = VT_DISPATCH;
1675  V_DISPATCH(var) = val2dispatch(val);
1676  break;
1677  }
1678 }
1679 
1680 static void
1681 ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt)
1682 {
1683  if (val == Qnil) {
1684  if (vt == VT_VARIANT) {
1685  ole_val2variant2(val, var);
1686  } else {
1687  V_VT(var) = (vt & ~VT_BYREF);
1688  if (V_VT(var) == VT_DISPATCH) {
1689  V_DISPATCH(var) = NULL;
1690  } else if (V_VT(var) == VT_UNKNOWN) {
1691  V_UNKNOWN(var) = NULL;
1692  }
1693  }
1694  return;
1695  }
1696 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1697  switch(vt & ~VT_BYREF) {
1698  case VT_I8:
1699  V_VT(var) = VT_I8;
1700  V_I8(var) = NUM2I8 (val);
1701  break;
1702  case VT_UI8:
1703  V_VT(var) = VT_UI8;
1704  V_UI8(var) = NUM2UI8(val);
1705  break;
1706  default:
1707  ole_val2variant2(val, var);
1708  break;
1709  }
1710 #else /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
1711  ole_val2variant2(val, var);
1712 #endif
1713 }
1714 
1715 static void
1717 {
1718  switch (TYPE(val)) {
1719  case T_STRING:
1720  if (V_VT(var) == (VT_BSTR | VT_BYREF)) {
1721  *V_BSTRREF(var) = ole_vstr2wc(val);
1722  }
1723  break;
1724  case T_FIXNUM:
1725  switch(V_VT(var)) {
1726  case (VT_UI1 | VT_BYREF) :
1727  *V_UI1REF(var) = NUM2CHR(val);
1728  break;
1729  case (VT_I2 | VT_BYREF) :
1730  *V_I2REF(var) = (short)NUM2INT(val);
1731  break;
1732  case (VT_I4 | VT_BYREF) :
1733  *V_I4REF(var) = NUM2INT(val);
1734  break;
1735  case (VT_R4 | VT_BYREF) :
1736  *V_R4REF(var) = (float)NUM2INT(val);
1737  break;
1738  case (VT_R8 | VT_BYREF) :
1739  *V_R8REF(var) = NUM2INT(val);
1740  break;
1741  default:
1742  break;
1743  }
1744  break;
1745  case T_FLOAT:
1746  switch(V_VT(var)) {
1747  case (VT_I2 | VT_BYREF) :
1748  *V_I2REF(var) = (short)NUM2INT(val);
1749  break;
1750  case (VT_I4 | VT_BYREF) :
1751  *V_I4REF(var) = NUM2INT(val);
1752  break;
1753  case (VT_R4 | VT_BYREF) :
1754  *V_R4REF(var) = (float)NUM2DBL(val);
1755  break;
1756  case (VT_R8 | VT_BYREF) :
1757  *V_R8REF(var) = NUM2DBL(val);
1758  break;
1759  default:
1760  break;
1761  }
1762  break;
1763  case T_BIGNUM:
1764  if (V_VT(var) == (VT_R8 | VT_BYREF)) {
1765  *V_R8REF(var) = rb_big2dbl(val);
1766  }
1767  break;
1768  case T_TRUE:
1769  if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
1770  *V_BOOLREF(var) = VARIANT_TRUE;
1771  }
1772  break;
1773  case T_FALSE:
1774  if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
1775  *V_BOOLREF(var) = VARIANT_FALSE;
1776  }
1777  break;
1778  default:
1779  break;
1780  }
1781 }
1782 
1783 static void
1784 ole_set_byref(VARIANT *realvar, VARIANT *var, VARTYPE vt)
1785 {
1786  V_VT(var) = vt;
1787  if (vt == (VT_VARIANT|VT_BYREF)) {
1788  V_VARIANTREF(var) = realvar;
1789  } else {
1790  if (V_VT(realvar) != (vt & ~VT_BYREF)) {
1791  rb_raise(eWIN32OLERuntimeError, "variant type mismatch");
1792  }
1793  switch(vt & ~VT_BYREF) {
1794  case VT_I1:
1795  V_I1REF(var) = &V_I1(realvar);
1796  break;
1797  case VT_UI1:
1798  V_UI1REF(var) = &V_UI1(realvar);
1799  break;
1800  case VT_I2:
1801  V_I2REF(var) = &V_I2(realvar);
1802  break;
1803  case VT_UI2:
1804  V_UI2REF(var) = &V_UI2(realvar);
1805  break;
1806  case VT_I4:
1807  V_I4REF(var) = &V_I4(realvar);
1808  break;
1809  case VT_UI4:
1810  V_UI4REF(var) = &V_UI4(realvar);
1811  break;
1812  case VT_R4:
1813  V_R4REF(var) = &V_R4(realvar);
1814  break;
1815  case VT_R8:
1816  V_R8REF(var) = &V_R8(realvar);
1817  break;
1818 
1819 #if (_MSC_VER >= 1300)
1820  case VT_I8:
1821  V_I8REF(var) = &V_I8(realvar);
1822  break;
1823  case VT_UI8:
1824  V_UI8REF(var) = &V_UI8(realvar);
1825  break;
1826 #endif
1827  case VT_INT:
1828  V_INTREF(var) = &V_INT(realvar);
1829  break;
1830 
1831  case VT_UINT:
1832  V_UINTREF(var) = &V_UINT(realvar);
1833  break;
1834 
1835  case VT_CY:
1836  V_CYREF(var) = &V_CY(realvar);
1837  break;
1838  case VT_DATE:
1839  V_DATEREF(var) = &V_DATE(realvar);
1840  break;
1841  case VT_BSTR:
1842  V_BSTRREF(var) = &V_BSTR(realvar);
1843  break;
1844  case VT_DISPATCH:
1845  V_DISPATCHREF(var) = &V_DISPATCH(realvar);
1846  break;
1847  case VT_ERROR:
1848  V_ERRORREF(var) = &V_ERROR(realvar);
1849  break;
1850  case VT_BOOL:
1851  V_BOOLREF(var) = &V_BOOL(realvar);
1852  break;
1853  case VT_UNKNOWN:
1854  V_UNKNOWNREF(var) = &V_UNKNOWN(realvar);
1855  break;
1856  case VT_ARRAY:
1857  V_ARRAYREF(var) = &V_ARRAY(realvar);
1858  break;
1859  default:
1860  rb_raise(eWIN32OLERuntimeError, "unknown type specified(setting BYREF):%d", vt);
1861  break;
1862  }
1863  }
1864 }
1865 
1866 static void
1867 ole_val2olevariantdata(VALUE val, VARTYPE vt, struct olevariantdata *pvar)
1868 {
1869  HRESULT hr = S_OK;
1870 
1871  if (((vt & ~VT_BYREF) == (VT_ARRAY | VT_UI1)) && TYPE(val) == T_STRING) {
1872  long len = RSTRING_LEN(val);
1873  void *pdest = NULL;
1874  SAFEARRAY *p = NULL;
1875  SAFEARRAY *psa = SafeArrayCreateVector(VT_UI1, 0, len);
1876  if (!psa) {
1877  rb_raise(rb_eRuntimeError, "fail to SafeArrayCreateVector");
1878  }
1879  hr = SafeArrayAccessData(psa, &pdest);
1880  if (SUCCEEDED(hr)) {
1881  memcpy(pdest, RSTRING_PTR(val), len);
1882  SafeArrayUnaccessData(psa);
1883  V_VT(&(pvar->realvar)) = (vt & ~VT_BYREF);
1884  p = V_ARRAY(&(pvar->realvar));
1885  if (p != NULL) {
1886  SafeArrayDestroy(p);
1887  }
1888  V_ARRAY(&(pvar->realvar)) = psa;
1889  if (vt & VT_BYREF) {
1890  V_VT(&(pvar->var)) = vt;
1891  V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
1892  } else {
1893  hr = VariantCopy(&(pvar->var), &(pvar->realvar));
1894  }
1895  } else {
1896  if (psa)
1897  SafeArrayDestroy(psa);
1898  }
1899  } else if (vt & VT_ARRAY) {
1900  if (val == Qnil) {
1901  V_VT(&(pvar->var)) = vt;
1902  if (vt & VT_BYREF) {
1903  V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
1904  }
1905  } else {
1906  hr = ole_val_ary2variant_ary(val, &(pvar->realvar), (VARTYPE)(vt & ~VT_BYREF));
1907  if (SUCCEEDED(hr)) {
1908  if (vt & VT_BYREF) {
1909  V_VT(&(pvar->var)) = vt;
1910  V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
1911  } else {
1912  hr = VariantCopy(&(pvar->var), &(pvar->realvar));
1913  }
1914  }
1915  }
1916 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1917  } else if ( (vt & ~VT_BYREF) == VT_I8 || (vt & ~VT_BYREF) == VT_UI8) {
1918  ole_val2variant_ex(val, &(pvar->realvar), (vt & ~VT_BYREF));
1919  ole_val2variant_ex(val, &(pvar->var), (vt & ~VT_BYREF));
1920  V_VT(&(pvar->var)) = vt;
1921  if (vt & VT_BYREF) {
1922  ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
1923  }
1924 #endif
1925  } else {
1926  if (val == Qnil) {
1927  V_VT(&(pvar->var)) = vt;
1928  if (vt == (VT_BYREF | VT_VARIANT)) {
1929  ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
1930  } else {
1931  V_VT(&(pvar->realvar)) = vt & ~VT_BYREF;
1932  if (vt & VT_BYREF) {
1933  ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
1934  }
1935  }
1936  } else {
1937  ole_val2variant_ex(val, &(pvar->realvar), (VARTYPE)(vt & ~VT_BYREF));
1938  if (vt == (VT_BYREF | VT_VARIANT)) {
1939  ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
1940  } else if (vt & VT_BYREF) {
1941  if ( (vt & ~VT_BYREF) != V_VT(&(pvar->realvar))) {
1942  hr = VariantChangeTypeEx(&(pvar->realvar), &(pvar->realvar),
1943  cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF));
1944  }
1945  if (SUCCEEDED(hr)) {
1946  ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
1947  }
1948  } else {
1949  if (vt == V_VT(&(pvar->realvar))) {
1950  hr = VariantCopy(&(pvar->var), &(pvar->realvar));
1951  } else {
1952  hr = VariantChangeTypeEx(&(pvar->var), &(pvar->realvar),
1953  cWIN32OLE_lcid, 0, vt);
1954  }
1955  }
1956  }
1957  }
1958  if (FAILED(hr)) {
1959  ole_raise(hr, eWIN32OLERuntimeError, "failed to change type");
1960  }
1961 }
1962 
1963 static void
1965 {
1966  g_nil_to = VT_EMPTY;
1967  ole_val2variant(val, var);
1968  g_nil_to = VT_ERROR;
1969 }
1970 
1971 static VALUE
1972 make_inspect(const char *class_name, VALUE detail)
1973 {
1974  VALUE str;
1975  str = rb_str_new2("#<");
1976  rb_str_cat2(str, class_name);
1977  rb_str_cat2(str, ":");
1978  rb_str_concat(str, detail);
1979  rb_str_cat2(str, ">");
1980  return str;
1981 }
1982 
1983 static VALUE
1984 default_inspect(VALUE self, const char *class_name)
1985 {
1986  VALUE detail = rb_funcall(self, rb_intern("to_s"), 0);
1987  return make_inspect(class_name, detail);
1988 }
1989 
1990 static VALUE
1991 ole_set_member(VALUE self, IDispatch *dispatch)
1992 {
1993  struct oledata *pole;
1994  Data_Get_Struct(self, struct oledata, pole);
1995  if (pole->pDispatch) {
1996  OLE_RELEASE(pole->pDispatch);
1997  pole->pDispatch = NULL;
1998  }
1999  pole->pDispatch = dispatch;
2000  return self;
2001 }
2002 
2003 
2004 static VALUE
2006 {
2007  struct oledata *pole;
2008  VALUE obj;
2009  ole_initialize();
2010  obj = Data_Make_Struct(klass,struct oledata,0,ole_free,pole);
2011  pole->pDispatch = NULL;
2012  return obj;
2013 }
2014 
2015 static VALUE
2017 {
2018  VALUE obj = fole_s_allocate(klass);
2019  ole_set_member(obj, pDispatch);
2020  return obj;
2021 }
2022 
2023 static VALUE
2024 ary_new_dim(VALUE myary, long *pid, long *plb, long dim) {
2025  long i;
2026  VALUE obj = Qnil;
2027  VALUE pobj = Qnil;
2028  long *ids = ALLOC_N(long, dim);
2029  if (!ids) {
2030  rb_raise(rb_eRuntimeError, "memory allocation error");
2031  }
2032  for(i = 0; i < dim; i++) {
2033  ids[i] = pid[i] - plb[i];
2034  }
2035  obj = myary;
2036  pobj = myary;
2037  for(i = 0; i < dim-1; i++) {
2038  obj = rb_ary_entry(pobj, ids[i]);
2039  if (obj == Qnil) {
2040  rb_ary_store(pobj, ids[i], rb_ary_new());
2041  }
2042  obj = rb_ary_entry(pobj, ids[i]);
2043  pobj = obj;
2044  }
2045  if (ids) free(ids);
2046  return obj;
2047 }
2048 
2049 static void
2050 ary_store_dim(VALUE myary, long *pid, long *plb, long dim, VALUE val) {
2051  long id = pid[dim - 1] - plb[dim - 1];
2052  VALUE obj = ary_new_dim(myary, pid, plb, dim);
2053  rb_ary_store(obj, id, val);
2054 }
2055 
2056 static VALUE
2057 ole_variant2val(VARIANT *pvar)
2058 {
2059  VALUE obj = Qnil;
2060  HRESULT hr;
2061  while ( V_VT(pvar) == (VT_BYREF | VT_VARIANT) )
2062  pvar = V_VARIANTREF(pvar);
2063 
2064  if(V_ISARRAY(pvar)) {
2065  SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar);
2066  UINT i = 0;
2067  long *pid, *plb, *pub;
2068  VARIANT variant;
2069  VALUE val;
2070  UINT dim = 0;
2071  if (!psa) {
2072  return obj;
2073  }
2074  dim = SafeArrayGetDim(psa);
2075  VariantInit(&variant);
2076  V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF;
2077 
2078  pid = ALLOC_N(long, dim);
2079  plb = ALLOC_N(long, dim);
2080  pub = ALLOC_N(long, dim);
2081 
2082  if(!pid || !plb || !pub) {
2083  if(pid) free(pid);
2084  if(plb) free(plb);
2085  if(pub) free(pub);
2086  rb_raise(rb_eRuntimeError, "memory allocation error");
2087  }
2088 
2089  for(i = 0; i < dim; ++i) {
2090  SafeArrayGetLBound(psa, i+1, &plb[i]);
2091  SafeArrayGetLBound(psa, i+1, &pid[i]);
2092  SafeArrayGetUBound(psa, i+1, &pub[i]);
2093  }
2094  hr = SafeArrayLock(psa);
2095  if (SUCCEEDED(hr)) {
2096  obj = rb_ary_new();
2097  i = 0;
2098  while (i < dim) {
2099  ary_new_dim(obj, pid, plb, dim);
2100  hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
2101  if (SUCCEEDED(hr)) {
2102  val = ole_variant2val(&variant);
2103  ary_store_dim(obj, pid, plb, dim, val);
2104  }
2105  for (i = 0; i < dim; ++i) {
2106  if (++pid[i] <= pub[i])
2107  break;
2108  pid[i] = plb[i];
2109  }
2110  }
2111  SafeArrayUnlock(psa);
2112  }
2113  if(pid) free(pid);
2114  if(plb) free(plb);
2115  if(pub) free(pub);
2116  return obj;
2117  }
2118  switch(V_VT(pvar) & ~VT_BYREF){
2119  case VT_EMPTY:
2120  break;
2121  case VT_NULL:
2122  break;
2123  case VT_I1:
2124  if(V_ISBYREF(pvar))
2125  obj = INT2NUM((long)*V_I1REF(pvar));
2126  else
2127  obj = INT2NUM((long)V_I1(pvar));
2128  break;
2129 
2130  case VT_UI1:
2131  if(V_ISBYREF(pvar))
2132  obj = INT2NUM((long)*V_UI1REF(pvar));
2133  else
2134  obj = INT2NUM((long)V_UI1(pvar));
2135  break;
2136 
2137  case VT_I2:
2138  if(V_ISBYREF(pvar))
2139  obj = INT2NUM((long)*V_I2REF(pvar));
2140  else
2141  obj = INT2NUM((long)V_I2(pvar));
2142  break;
2143 
2144  case VT_UI2:
2145  if(V_ISBYREF(pvar))
2146  obj = INT2NUM((long)*V_UI2REF(pvar));
2147  else
2148  obj = INT2NUM((long)V_UI2(pvar));
2149  break;
2150 
2151  case VT_I4:
2152  if(V_ISBYREF(pvar))
2153  obj = INT2NUM((long)*V_I4REF(pvar));
2154  else
2155  obj = INT2NUM((long)V_I4(pvar));
2156  break;
2157 
2158  case VT_UI4:
2159  if(V_ISBYREF(pvar))
2160  obj = INT2NUM((long)*V_UI4REF(pvar));
2161  else
2162  obj = INT2NUM((long)V_UI4(pvar));
2163  break;
2164 
2165  case VT_INT:
2166  if(V_ISBYREF(pvar))
2167  obj = INT2NUM((long)*V_INTREF(pvar));
2168  else
2169  obj = INT2NUM((long)V_INT(pvar));
2170  break;
2171 
2172  case VT_UINT:
2173  if(V_ISBYREF(pvar))
2174  obj = INT2NUM((long)*V_UINTREF(pvar));
2175  else
2176  obj = INT2NUM((long)V_UINT(pvar));
2177  break;
2178 
2179 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
2180  case VT_I8:
2181  if(V_ISBYREF(pvar))
2182 #if (_MSC_VER >= 1300)
2183  obj = I8_2_NUM(*V_I8REF(pvar));
2184 #else
2185  obj = Qnil;
2186 #endif
2187  else
2188  obj = I8_2_NUM(V_I8(pvar));
2189  break;
2190  case VT_UI8:
2191  if(V_ISBYREF(pvar))
2192 #if (_MSC_VER >= 1300)
2193  obj = UI8_2_NUM(*V_UI8REF(pvar));
2194 #else
2195  obj = Qnil;
2196 #endif
2197  else
2198  obj = UI8_2_NUM(V_UI8(pvar));
2199  break;
2200 #endif /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
2201 
2202  case VT_R4:
2203  if(V_ISBYREF(pvar))
2204  obj = rb_float_new(*V_R4REF(pvar));
2205  else
2206  obj = rb_float_new(V_R4(pvar));
2207  break;
2208 
2209  case VT_R8:
2210  if(V_ISBYREF(pvar))
2211  obj = rb_float_new(*V_R8REF(pvar));
2212  else
2213  obj = rb_float_new(V_R8(pvar));
2214  break;
2215 
2216  case VT_BSTR:
2217  {
2218  if(V_ISBYREF(pvar))
2219  obj = ole_wc2vstr(*V_BSTRREF(pvar), FALSE);
2220  else
2221  obj = ole_wc2vstr(V_BSTR(pvar), FALSE);
2222  break;
2223  }
2224 
2225  case VT_ERROR:
2226  if(V_ISBYREF(pvar))
2227  obj = INT2NUM(*V_ERRORREF(pvar));
2228  else
2229  obj = INT2NUM(V_ERROR(pvar));
2230  break;
2231 
2232  case VT_BOOL:
2233  if (V_ISBYREF(pvar))
2234  obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse);
2235  else
2236  obj = (V_BOOL(pvar) ? Qtrue : Qfalse);
2237  break;
2238 
2239  case VT_DISPATCH:
2240  {
2241  IDispatch *pDispatch;
2242 
2243  if (V_ISBYREF(pvar))
2244  pDispatch = *V_DISPATCHREF(pvar);
2245  else
2246  pDispatch = V_DISPATCH(pvar);
2247 
2248  if (pDispatch != NULL ) {
2249  OLE_ADDREF(pDispatch);
2250  obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
2251  }
2252  break;
2253  }
2254 
2255  case VT_UNKNOWN:
2256  {
2257  /* get IDispatch interface from IUnknown interface */
2258  IUnknown *punk;
2259  IDispatch *pDispatch;
2260  void *p;
2261  HRESULT hr;
2262 
2263  if (V_ISBYREF(pvar))
2264  punk = *V_UNKNOWNREF(pvar);
2265  else
2266  punk = V_UNKNOWN(pvar);
2267 
2268  if(punk != NULL) {
2269  hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch, &p);
2270  if(SUCCEEDED(hr)) {
2271  pDispatch = p;
2272  obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
2273  }
2274  }
2275  break;
2276  }
2277 
2278  case VT_DATE:
2279  {
2280  DATE date;
2281  if(V_ISBYREF(pvar))
2282  date = *V_DATEREF(pvar);
2283  else
2284  date = V_DATE(pvar);
2285 
2286  obj = vtdate2rbtime(date);
2287  break;
2288  }
2289  case VT_CY:
2290  default:
2291  {
2292  HRESULT hr;
2293  VARIANT variant;
2294  VariantInit(&variant);
2295  hr = VariantChangeTypeEx(&variant, pvar,
2296  cWIN32OLE_lcid, 0, VT_BSTR);
2297  if (SUCCEEDED(hr) && V_VT(&variant) == VT_BSTR) {
2298  obj = ole_wc2vstr(V_BSTR(&variant), FALSE);
2299  }
2300  VariantClear(&variant);
2301  break;
2302  }
2303  }
2304  return obj;
2305 }
2306 
2307 static LONG
2308 reg_open_key(HKEY hkey, const char *name, HKEY *phkey)
2309 {
2310  return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey);
2311 }
2312 
2313 static LONG
2314 reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey)
2315 {
2316  return reg_open_key(hkey, StringValuePtr(key), phkey);
2317 }
2318 
2319 static VALUE
2320 reg_enum_key(HKEY hkey, DWORD i)
2321 {
2322  char buf[BUFSIZ + 1];
2323  DWORD size_buf = sizeof(buf);
2324  FILETIME ft;
2325  LONG err = RegEnumKeyEx(hkey, i, buf, &size_buf,
2326  NULL, NULL, NULL, &ft);
2327  if(err == ERROR_SUCCESS) {
2328  buf[BUFSIZ] = '\0';
2329  return rb_str_new2(buf);
2330  }
2331  return Qnil;
2332 }
2333 
2334 static VALUE
2335 reg_get_val(HKEY hkey, const char *subkey)
2336 {
2337  char *pbuf;
2338  DWORD dwtype = 0;
2339  DWORD size = 0;
2340  VALUE val = Qnil;
2341  LONG err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, NULL, &size);
2342 
2343  if (err == ERROR_SUCCESS) {
2344  pbuf = ALLOC_N(char, size + 1);
2345  err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, (BYTE *)pbuf, &size);
2346  if (err == ERROR_SUCCESS) {
2347  pbuf[size] = '\0';
2348  if (dwtype == REG_EXPAND_SZ) {
2349  char* pbuf2 = (char *)pbuf;
2350  DWORD len = ExpandEnvironmentStrings(pbuf2, NULL, 0);
2351  pbuf = ALLOC_N(char, len + 1);
2352  ExpandEnvironmentStrings(pbuf2, pbuf, len + 1);
2353  free(pbuf2);
2354  }
2355  val = rb_str_new2((char *)pbuf);
2356  }
2357  free(pbuf);
2358  }
2359  return val;
2360 }
2361 
2362 static VALUE
2363 reg_get_val2(HKEY hkey, const char *subkey)
2364 {
2365  HKEY hsubkey;
2366  LONG err;
2367  VALUE val = Qnil;
2368  err = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &hsubkey);
2369  if (err == ERROR_SUCCESS) {
2370  val = reg_get_val(hsubkey, NULL);
2371  RegCloseKey(hsubkey);
2372  }
2373  if (val == Qnil) {
2374  val = reg_get_val(hkey, subkey);
2375  }
2376  return val;
2377 }
2378 
2379 static VALUE
2381 {
2382  VALUE path = Qnil;
2383  path = reg_get_val2(hkey, "win64");
2384  if (path != Qnil) {
2385  return path;
2386  }
2387  path = reg_get_val2(hkey, "win32");
2388  if (path != Qnil) {
2389  return path;
2390  }
2391  path = reg_get_val2(hkey, "win16");
2392  return path;
2393 }
2394 
2395 static VALUE
2397 {
2398  HKEY hroot, hclsid;
2399  LONG err;
2400  VALUE typelib;
2401  char path[MAX_PATH + 1];
2402 
2403  err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hroot);
2404  if (err != ERROR_SUCCESS) {
2405  return Qnil;
2406  }
2407  err = reg_open_key(hroot, StringValuePtr(ole), &hclsid);
2408  if (err != ERROR_SUCCESS) {
2409  RegCloseKey(hroot);
2410  return Qnil;
2411  }
2412  typelib = reg_get_val2(hclsid, "InprocServer32");
2413  RegCloseKey(hroot);
2414  RegCloseKey(hclsid);
2415  if (typelib != Qnil) {
2416  ExpandEnvironmentStrings(StringValuePtr(typelib), path, sizeof(path));
2417  path[MAX_PATH] = '\0';
2418  typelib = rb_str_new2(path);
2419  }
2420  return typelib;
2421 }
2422 
2423 static VALUE
2425 {
2426  HKEY htypelib, hclsid, hversion, hlang;
2427  double fver;
2428  DWORD i, j, k;
2429  LONG err;
2430  BOOL found = FALSE;
2431  VALUE typelib;
2432  VALUE file = Qnil;
2433  VALUE clsid;
2434  VALUE ver;
2435  VALUE lang;
2436 
2437  err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
2438  if(err != ERROR_SUCCESS) {
2439  return Qnil;
2440  }
2441  for(i = 0; !found; i++) {
2442  clsid = reg_enum_key(htypelib, i);
2443  if (clsid == Qnil)
2444  break;
2445  err = reg_open_vkey(htypelib, clsid, &hclsid);
2446  if (err != ERROR_SUCCESS)
2447  continue;
2448  fver = 0;
2449  for(j = 0; !found; j++) {
2450  ver = reg_enum_key(hclsid, j);
2451  if (ver == Qnil)
2452  break;
2453  err = reg_open_vkey(hclsid, ver, &hversion);
2454  if (err != ERROR_SUCCESS || fver > atof(StringValuePtr(ver)))
2455  continue;
2456  fver = atof(StringValuePtr(ver));
2457  typelib = reg_get_val(hversion, NULL);
2458  if (typelib == Qnil)
2459  continue;
2460  if (rb_str_cmp(typelib, ole) == 0) {
2461  for(k = 0; !found; k++) {
2462  lang = reg_enum_key(hversion, k);
2463  if (lang == Qnil)
2464  break;
2465  err = reg_open_vkey(hversion, lang, &hlang);
2466  if (err == ERROR_SUCCESS) {
2467  if ((file = reg_get_typelib_file_path(hlang)) != Qnil)
2468  found = TRUE;
2469  RegCloseKey(hlang);
2470  }
2471  }
2472  }
2473  RegCloseKey(hversion);
2474  }
2475  RegCloseKey(hclsid);
2476  }
2477  RegCloseKey(htypelib);
2478  return file;
2479 }
2480 
2481 static VALUE
2483 {
2484  VALUE file = typelib_file_from_clsid(ole);
2485  if (file != Qnil) {
2486  return file;
2487  }
2488  return typelib_file_from_typelib(ole);
2489 }
2490 
2491 static void
2492 ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self)
2493 {
2494  unsigned int count;
2495  unsigned int index;
2496  int iVar;
2497  ITypeInfo *pTypeInfo;
2498  TYPEATTR *pTypeAttr;
2499  VARDESC *pVarDesc;
2500  HRESULT hr;
2501  unsigned int len;
2502  BSTR bstr;
2503  char *pName = NULL;
2504  VALUE val;
2505  VALUE constant;
2506  ID id;
2507  constant = rb_hash_new();
2508  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
2509  for (index = 0; index < count; index++) {
2510  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, index, &pTypeInfo);
2511  if (FAILED(hr))
2512  continue;
2513  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
2514  if(FAILED(hr)) {
2515  OLE_RELEASE(pTypeInfo);
2516  continue;
2517  }
2518  for(iVar = 0; iVar < pTypeAttr->cVars; iVar++) {
2519  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, iVar, &pVarDesc);
2520  if(FAILED(hr))
2521  continue;
2522  if(pVarDesc->varkind == VAR_CONST &&
2523  !(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
2524  VARFLAG_FRESTRICTED |
2525  VARFLAG_FNONBROWSABLE))) {
2526  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
2527  1, &len);
2528  if(FAILED(hr) || len == 0 || !bstr)
2529  continue;
2530  pName = ole_wc2mb(bstr);
2531  val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
2532  *pName = toupper((int)*pName);
2533  id = rb_intern(pName);
2534  if (rb_is_const_id(id)) {
2535  rb_define_const(klass, pName, val);
2536  }
2537  else {
2538  rb_hash_aset(constant, rb_str_new2(pName), val);
2539  }
2540  SysFreeString(bstr);
2541  if(pName) {
2542  free(pName);
2543  pName = NULL;
2544  }
2545  }
2546  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
2547  }
2548  pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
2549  OLE_RELEASE(pTypeInfo);
2550  }
2551  rb_define_const(klass, "CONSTANTS", constant);
2552 }
2553 
2554 static HRESULT
2555 clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid)
2556 {
2557  HKEY hlm;
2558  HKEY hpid;
2559  VALUE subkey;
2560  LONG err;
2561  char clsid[100];
2562  OLECHAR *pbuf;
2563  DWORD len;
2564  DWORD dwtype;
2565  HRESULT hr = S_OK;
2566  err = RegConnectRegistry(StringValuePtr(host), HKEY_LOCAL_MACHINE, &hlm);
2567  if (err != ERROR_SUCCESS)
2568  return HRESULT_FROM_WIN32(err);
2569  subkey = rb_str_new2("SOFTWARE\\Classes\\");
2570  rb_str_concat(subkey, com);
2571  rb_str_cat2(subkey, "\\CLSID");
2572  err = RegOpenKeyEx(hlm, StringValuePtr(subkey), 0, KEY_READ, &hpid);
2573  if (err != ERROR_SUCCESS)
2574  hr = HRESULT_FROM_WIN32(err);
2575  else {
2576  len = sizeof(clsid);
2577  err = RegQueryValueEx(hpid, "", NULL, &dwtype, (BYTE *)clsid, &len);
2578  if (err == ERROR_SUCCESS && dwtype == REG_SZ) {
2579  pbuf = ole_mb2wc(clsid, -1);
2580  hr = CLSIDFromString(pbuf, pclsid);
2581  SysFreeString(pbuf);
2582  }
2583  else {
2584  hr = HRESULT_FROM_WIN32(err);
2585  }
2586  RegCloseKey(hpid);
2587  }
2588  RegCloseKey(hlm);
2589  return hr;
2590 }
2591 
2592 static VALUE
2594 {
2595  VALUE ole, host, others;
2596  HRESULT hr;
2597  CLSID clsid;
2598  OLECHAR *pbuf;
2599 
2600  COSERVERINFO serverinfo;
2601  MULTI_QI multi_qi;
2602  DWORD clsctx = CLSCTX_REMOTE_SERVER;
2603 
2604  if (!gole32)
2605  gole32 = LoadLibrary("OLE32");
2606  if (!gole32)
2607  rb_raise(rb_eRuntimeError, "failed to load OLE32");
2608  if (!gCoCreateInstanceEx)
2609  gCoCreateInstanceEx = (FNCOCREATEINSTANCEEX*)
2610  GetProcAddress(gole32, "CoCreateInstanceEx");
2611  if (!gCoCreateInstanceEx)
2612  rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment");
2613  rb_scan_args(argc, argv, "2*", &ole, &host, &others);
2614 
2615  pbuf = ole_vstr2wc(ole);
2616  hr = CLSIDFromProgID(pbuf, &clsid);
2617  if (FAILED(hr))
2618  hr = clsid_from_remote(host, ole, &clsid);
2619  if (FAILED(hr))
2620  hr = CLSIDFromString(pbuf, &clsid);
2621  SysFreeString(pbuf);
2622  if (FAILED(hr))
2624  "unknown OLE server: `%s'",
2625  StringValuePtr(ole));
2626  memset(&serverinfo, 0, sizeof(COSERVERINFO));
2627  serverinfo.pwszName = ole_vstr2wc(host);
2628  memset(&multi_qi, 0, sizeof(MULTI_QI));
2629  multi_qi.pIID = &IID_IDispatch;
2630  hr = gCoCreateInstanceEx(&clsid, NULL, clsctx, &serverinfo, 1, &multi_qi);
2631  SysFreeString(serverinfo.pwszName);
2632  if (FAILED(hr))
2634  "failed to create DCOM server `%s' in `%s'",
2635  StringValuePtr(ole),
2636  StringValuePtr(host));
2637 
2638  ole_set_member(self, (IDispatch*)multi_qi.pItf);
2639  return self;
2640 }
2641 
2642 static VALUE
2643 ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self)
2644 {
2645  IBindCtx *pBindCtx;
2646  IMoniker *pMoniker;
2647  IDispatch *pDispatch;
2648  void *p;
2649  HRESULT hr;
2650  OLECHAR *pbuf;
2651  ULONG eaten = 0;
2652 
2653  ole_initialize();
2654 
2655  hr = CreateBindCtx(0, &pBindCtx);
2656  if(FAILED(hr)) {
2658  "failed to create bind context");
2659  }
2660 
2661  pbuf = ole_vstr2wc(moniker);
2662  hr = MkParseDisplayName(pBindCtx, pbuf, &eaten, &pMoniker);
2663  SysFreeString(pbuf);
2664  if(FAILED(hr)) {
2665  OLE_RELEASE(pBindCtx);
2667  "failed to parse display name of moniker `%s'",
2668  StringValuePtr(moniker));
2669  }
2670  hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL,
2671  &IID_IDispatch, &p);
2672  pDispatch = p;
2673  OLE_RELEASE(pMoniker);
2674  OLE_RELEASE(pBindCtx);
2675 
2676  if(FAILED(hr)) {
2678  "failed to bind moniker `%s'",
2679  StringValuePtr(moniker));
2680  }
2681  return create_win32ole_object(self, pDispatch, argc, argv);
2682 }
2683 
2684 /*
2685  * call-seq:
2686  * WIN32OLE.connect( ole ) --> aWIN32OLE
2687  *
2688  * Returns running OLE Automation object or WIN32OLE object from moniker.
2689  * 1st argument should be OLE program id or class id or moniker.
2690  *
2691  * WIN32OLE.connect('Excel.Application') # => WIN32OLE object which represents running Excel.
2692  */
2693 static VALUE
2695 {
2696  VALUE svr_name;
2697  VALUE others;
2698  HRESULT hr;
2699  CLSID clsid;
2700  OLECHAR *pBuf;
2701  IDispatch *pDispatch;
2702  void *p;
2703  IUnknown *pUnknown;
2704 
2705  rb_secure(4);
2706  /* initialize to use OLE */
2707  ole_initialize();
2708 
2709  rb_scan_args(argc, argv, "1*", &svr_name, &others);
2710  SafeStringValue(svr_name);
2711  if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
2712  rb_raise(rb_eSecurityError, "Insecure Object Connection - %s",
2713  StringValuePtr(svr_name));
2714  }
2715 
2716  /* get CLSID from OLE server name */
2717  pBuf = ole_vstr2wc(svr_name);
2718  hr = CLSIDFromProgID(pBuf, &clsid);
2719  if(FAILED(hr)) {
2720  hr = CLSIDFromString(pBuf, &clsid);
2721  }
2722  SysFreeString(pBuf);
2723  if(FAILED(hr)) {
2724  return ole_bind_obj(svr_name, argc, argv, self);
2725  }
2726 
2727  hr = GetActiveObject(&clsid, 0, &pUnknown);
2728  if (FAILED(hr)) {
2730  "OLE server `%s' not running", StringValuePtr(svr_name));
2731  }
2732  hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch, &p);
2733  pDispatch = p;
2734  if(FAILED(hr)) {
2735  OLE_RELEASE(pUnknown);
2737  "failed to create WIN32OLE server `%s'",
2738  StringValuePtr(svr_name));
2739  }
2740 
2741  OLE_RELEASE(pUnknown);
2742 
2743  return create_win32ole_object(self, pDispatch, argc, argv);
2744 }
2745 
2746 /*
2747  * call-seq:
2748  * WIN32OLE.const_load( ole, mod = WIN32OLE)
2749  *
2750  * Defines the constants of OLE Automation server as mod's constants.
2751  * The first argument is WIN32OLE object or type library name.
2752  * If 2nd argument is omitted, the default is WIN32OLE.
2753  * The first letter of Ruby's constant variable name is upper case,
2754  * so constant variable name of WIN32OLE object is capitalized.
2755  * For example, the 'xlTop' constant of Excel is changed to 'XlTop'
2756  * in WIN32OLE.
2757  * If the first letter of constant variabl is not [A-Z], then
2758  * the constant is defined as CONSTANTS hash element.
2759  *
2760  * module EXCEL_CONST
2761  * end
2762  * excel = WIN32OLE.new('Excel.Application')
2763  * WIN32OLE.const_load(excel, EXCEL_CONST)
2764  * puts EXCEL_CONST::XlTop # => -4160
2765  * puts EXCEL_CONST::CONSTANTS['_xlDialogChartSourceData'] # => 541
2766  *
2767  * WIN32OLE.const_load(excel)
2768  * puts WIN32OLE::XlTop # => -4160
2769  *
2770  * module MSO
2771  * end
2772  * WIN32OLE.const_load('Microsoft Office 9.0 Object Library', MSO)
2773  * puts MSO::MsoLineSingle # => 1
2774  */
2775 static VALUE
2777 {
2778  VALUE ole;
2779  VALUE klass;
2780  struct oledata *pole;
2781  ITypeInfo *pTypeInfo;
2782  ITypeLib *pTypeLib;
2783  unsigned int index;
2784  HRESULT hr;
2785  OLECHAR *pBuf;
2786  VALUE file;
2787  LCID lcid = cWIN32OLE_lcid;
2788 
2789  rb_secure(4);
2790  rb_scan_args(argc, argv, "11", &ole, &klass);
2791  if (TYPE(klass) != T_CLASS &&
2792  TYPE(klass) != T_MODULE &&
2793  TYPE(klass) != T_NIL) {
2794  rb_raise(rb_eTypeError, "2nd parameter must be Class or Module");
2795  }
2796  if (rb_obj_is_kind_of(ole, cWIN32OLE)) {
2797  OLEData_Get_Struct(ole, pole);
2798  hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
2799  0, lcid, &pTypeInfo);
2800  if(FAILED(hr)) {
2801  ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
2802  }
2803  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
2804  if(FAILED(hr)) {
2805  OLE_RELEASE(pTypeInfo);
2806  ole_raise(hr, rb_eRuntimeError, "failed to GetContainingTypeLib");
2807  }
2808  OLE_RELEASE(pTypeInfo);
2809  if(TYPE(klass) != T_NIL) {
2810  ole_const_load(pTypeLib, klass, self);
2811  }
2812  else {
2813  ole_const_load(pTypeLib, cWIN32OLE, self);
2814  }
2815  OLE_RELEASE(pTypeLib);
2816  }
2817  else if(TYPE(ole) == T_STRING) {
2818  file = typelib_file(ole);
2819  if (file == Qnil) {
2820  file = ole;
2821  }
2822  pBuf = ole_vstr2wc(file);
2823  hr = LoadTypeLibEx(pBuf, REGKIND_NONE, &pTypeLib);
2824  SysFreeString(pBuf);
2825  if (FAILED(hr))
2826  ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx");
2827  if(TYPE(klass) != T_NIL) {
2828  ole_const_load(pTypeLib, klass, self);
2829  }
2830  else {
2831  ole_const_load(pTypeLib, cWIN32OLE, self);
2832  }
2833  OLE_RELEASE(pTypeLib);
2834  }
2835  else {
2836  rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE instance");
2837  }
2838  return Qnil;
2839 }
2840 
2841 static VALUE
2842 ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes)
2843 {
2844 
2845  long count;
2846  int i;
2847  HRESULT hr;
2848  BSTR bstr;
2849  ITypeInfo *pTypeInfo;
2850  VALUE type;
2851 
2852  rb_secure(4);
2853  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
2854  for (i = 0; i < count; i++) {
2855  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
2856  &bstr, NULL, NULL, NULL);
2857  if (FAILED(hr))
2858  continue;
2859 
2860  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
2861  if (FAILED(hr))
2862  continue;
2863 
2865  oletype_set_member(type, pTypeInfo, WC2VSTR(bstr));
2866 
2867  rb_ary_push(classes, type);
2868  OLE_RELEASE(pTypeInfo);
2869  }
2870  return classes;
2871 }
2872 
2873 static ULONG
2874 reference_count(struct oledata * pole)
2875 {
2876  ULONG n = 0;
2877  if(pole->pDispatch) {
2878  OLE_ADDREF(pole->pDispatch);
2879  n = OLE_RELEASE(pole->pDispatch);
2880  }
2881  return n;
2882 }
2883 
2884 /*
2885  * call-seq:
2886  * WIN32OLE.ole_reference_count(aWIN32OLE) --> number
2887  *
2888  * Returns reference counter of Dispatch interface of WIN32OLE object.
2889  * You should not use this method because this method
2890  * exists only for debugging WIN32OLE.
2891  */
2892 static VALUE
2894 {
2895  struct oledata * pole;
2896  OLEData_Get_Struct(obj, pole);
2897  return INT2NUM(reference_count(pole));
2898 }
2899 
2900 /*
2901  * call-seq:
2902  * WIN32OLE.ole_free(aWIN32OLE) --> number
2903  *
2904  * Invokes Release method of Dispatch interface of WIN32OLE object.
2905  * You should not use this method because this method
2906  * exists only for debugging WIN32OLE.
2907  * The return value is reference counter of OLE object.
2908  */
2909 static VALUE
2911 {
2912  ULONG n = 0;
2913  struct oledata * pole;
2914  OLEData_Get_Struct(obj, pole);
2915  if(pole->pDispatch) {
2916  if (reference_count(pole) > 0) {
2917  n = OLE_RELEASE(pole->pDispatch);
2918  }
2919  }
2920  return INT2NUM(n);
2921 }
2922 
2923 static HWND
2924 ole_show_help(VALUE helpfile, VALUE helpcontext)
2925 {
2926  FNHTMLHELP *pfnHtmlHelp;
2927  HWND hwnd = 0;
2928 
2929  if(!ghhctrl)
2930  ghhctrl = LoadLibrary("HHCTRL.OCX");
2931  if (!ghhctrl)
2932  return hwnd;
2933  pfnHtmlHelp = (FNHTMLHELP*)GetProcAddress(ghhctrl, "HtmlHelpA");
2934  if (!pfnHtmlHelp)
2935  return hwnd;
2936  hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
2937  0x0f, NUM2INT(helpcontext));
2938  if (hwnd == 0)
2939  hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
2940  0, NUM2INT(helpcontext));
2941  return hwnd;
2942 }
2943 
2944 /*
2945  * call-seq:
2946  * WIN32OLE.ole_show_help(obj [,helpcontext])
2947  *
2948  * Displays helpfile. The 1st argument specifies WIN32OLE_TYPE
2949  * object or WIN32OLE_METHOD object or helpfile.
2950  *
2951  * excel = WIN32OLE.new('Excel.Application')
2952  * typeobj = excel.ole_type
2953  * WIN32OLE.ole_show_help(typeobj)
2954  */
2955 static VALUE
2957 {
2958  VALUE target;
2959  VALUE helpcontext;
2960  VALUE helpfile;
2961  VALUE name;
2962  HWND hwnd;
2963  rb_scan_args(argc, argv, "11", &target, &helpcontext);
2964  if (rb_obj_is_kind_of(target, cWIN32OLE_TYPE) ||
2966  helpfile = rb_funcall(target, rb_intern("helpfile"), 0);
2967  if(strlen(StringValuePtr(helpfile)) == 0) {
2968  name = rb_ivar_get(target, rb_intern("name"));
2969  rb_raise(rb_eRuntimeError, "no helpfile of `%s'",
2970  StringValuePtr(name));
2971  }
2972  helpcontext = rb_funcall(target, rb_intern("helpcontext"), 0);
2973  } else {
2974  helpfile = target;
2975  }
2976  if (TYPE(helpfile) != T_STRING) {
2977  rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD)");
2978  }
2979  hwnd = ole_show_help(helpfile, helpcontext);
2980  if(hwnd == 0) {
2981  rb_raise(rb_eRuntimeError, "failed to open help file `%s'",
2982  StringValuePtr(helpfile));
2983  }
2984  return Qnil;
2985 }
2986 
2987 /*
2988  * call-seq:
2989  * WIN32OLE.codepage
2990  *
2991  * Returns current codepage.
2992  * WIN32OLE.codepage # => WIN32OLE::CP_ACP
2993  */
2994 static VALUE
2996 {
2997  return INT2FIX(cWIN32OLE_cp);
2998 }
2999 
3000 static BOOL CALLBACK
3002  if (strtoul(str, NULL, 10) == g_cp_to_check) {
3003  g_cp_installed = TRUE;
3004  return FALSE;
3005  }
3006  return TRUE;
3007 }
3008 
3009 static BOOL
3011 {
3013  g_cp_to_check = cp;
3014  EnumSystemCodePages(installed_code_page_proc, CP_INSTALLED);
3015  return g_cp_installed;
3016 }
3017 
3018 /*
3019  * call-seq:
3020  * WIN32OLE.codepage = CP
3021  *
3022  * Sets current codepage.
3023  * The WIN32OLE.codepage is initialized according to
3024  * Encoding.default_internal.
3025  * If Encoding.default_internal is nil then WIN32OLE.codepage
3026  * is initialized according to Encoding.default_external.
3027  *
3028  * WIN32OLE.codepage = WIN32OLE::CP_UTF8
3029  * WIN32OLE.codepage = 65001
3030  */
3031 static VALUE
3033 {
3034  UINT cp = FIX2INT(vcp);
3035  set_ole_codepage(cp);
3036  /*
3037  * Should this method return old codepage?
3038  */
3039  return Qnil;
3040 }
3041 
3042 /*
3043  * call-seq:
3044  * WIN32OLE.locale -> locale id.
3045  *
3046  * Returns current locale id (lcid). The default locale is
3047  * LOCALE_SYSTEM_DEFAULT.
3048  *
3049  * lcid = WIN32OLE.locale
3050  */
3051 static VALUE
3053 {
3054  return INT2FIX(cWIN32OLE_lcid);
3055 }
3056 
3057 static BOOL
3058 CALLBACK installed_lcid_proc(LPTSTR str)
3059 {
3060  if (strcmp(str, g_lcid_to_check) == 0) {
3062  return FALSE;
3063  }
3064  return TRUE;
3065 }
3066 
3067 static BOOL
3068 lcid_installed(LCID lcid)
3069 {
3071  snprintf(g_lcid_to_check, sizeof(g_lcid_to_check), "%08lx", lcid);
3072  EnumSystemLocales(installed_lcid_proc, LCID_INSTALLED);
3073  return g_lcid_installed;
3074 }
3075 
3076 /*
3077  * call-seq:
3078  * WIN32OLE.locale = lcid
3079  *
3080  * Sets current locale id (lcid).
3081  *
3082  * WIN32OLE.locale = 1033 # set locale English(U.S)
3083  * obj = WIN32OLE_VARIANT.new("$100,000", WIN32OLE::VARIANT::VT_CY)
3084  *
3085  */
3086 static VALUE
3088 {
3089  LCID lcid = FIX2INT(vlcid);
3090  if (lcid_installed(lcid)) {
3091  cWIN32OLE_lcid = lcid;
3092  } else {
3093  switch (lcid) {
3094  case LOCALE_SYSTEM_DEFAULT:
3095  case LOCALE_USER_DEFAULT:
3096  cWIN32OLE_lcid = lcid;
3097  break;
3098  default:
3099  rb_raise(eWIN32OLERuntimeError, "not installed locale: %u", (unsigned int)lcid);
3100  }
3101  }
3102  return Qnil;
3103 }
3104 
3105 /*
3106  * call-seq:
3107  * WIN32OLE.create_guid
3108  *
3109  * Creates GUID.
3110  * WIN32OLE.create_guid # => {1CB530F1-F6B1-404D-BCE6-1959BF91F4A8}
3111  */
3112 static VALUE
3114 {
3115  GUID guid;
3116  HRESULT hr;
3117  OLECHAR bstr[80];
3118  int len = 0;
3119  hr = CoCreateGuid(&guid);
3120  if (FAILED(hr)) {
3121  ole_raise(hr, eWIN32OLERuntimeError, "failed to create GUID");
3122  }
3123  len = StringFromGUID2(&guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
3124  if (len == 0) {
3125  rb_raise(rb_eRuntimeError, "failed to create GUID(buffer over)");
3126  }
3127  return ole_wc2vstr(bstr, FALSE);
3128 }
3129 
3130 /*
3131  * WIN32OLE.ole_initialize and WIN32OLE.ole_uninitialize
3132  * are used in win32ole.rb to fix the issue bug #2618 (ruby-core:27634).
3133  * You must not use thease method.
3134  */
3135 
3136 static void ole_pure_initialize()
3137 {
3138  HRESULT hr;
3139  hr = OleInitialize(NULL);
3140  if(FAILED(hr)) {
3141  ole_raise(hr, rb_eRuntimeError, "fail: OLE initialize");
3142  }
3143 }
3144 
3146 {
3147  OleUninitialize();
3148 }
3149 
3150 /* :nodoc */
3151 static VALUE
3153 {
3155  return Qnil;
3156 }
3157 
3158 /* :nodoc */
3159 static VALUE
3161 {
3163  return Qnil;
3164 }
3165 
3166 /*
3167  * Document-class: WIN32OLE
3168  *
3169  * <code>WIN32OLE</code> objects represent OLE Automation object in Ruby.
3170  *
3171  * By using WIN32OLE, you can access OLE server like VBScript.
3172  *
3173  * Here is sample script.
3174  *
3175  * require 'win32ole'
3176  *
3177  * excel = WIN32OLE.new('Excel.Application')
3178  * excel.visible = true
3179  * workbook = excel.Workbooks.Add();
3180  * worksheet = workbook.Worksheets(1);
3181  * worksheet.Range("A1:D1").value = ["North","South","East","West"];
3182  * worksheet.Range("A2:B2").value = [5.2, 10];
3183  * worksheet.Range("C2").value = 8;
3184  * worksheet.Range("D2").value = 20;
3185  *
3186  * range = worksheet.Range("A1:D2");
3187  * range.select
3188  * chart = workbook.Charts.Add;
3189  *
3190  * workbook.saved = true;
3191  *
3192  * excel.ActiveWorkbook.Close(0);
3193  * excel.Quit();
3194  *
3195  * Unfortunately, Win32OLE doesn't support the argument passed by
3196  * reference directly.
3197  * Instead, Win32OLE provides WIN32OLE::ARGV.
3198  * If you want to get the result value of argument passed by reference,
3199  * you can use WIN32OLE::ARGV.
3200  *
3201  * oleobj.method(arg1, arg2, refargv3)
3202  * puts WIN32OLE::ARGV[2] # the value of refargv3 after called oleobj.method
3203  *
3204  */
3205 
3206 /*
3207  * call-seq:
3208  * WIN32OLE.new(server, [host]) -> WIN32OLE object
3209  *
3210  * Returns a new WIN32OLE object(OLE Automation object).
3211  * The first argument server specifies OLE Automation server.
3212  * The first argument should be CLSID or PROGID.
3213  * If second argument host specified, then returns OLE Automation
3214  * object on host.
3215  *
3216  * WIN32OLE.new('Excel.Application') # => Excel OLE Automation WIN32OLE object.
3217  * WIN32OLE.new('{00024500-0000-0000-C000-000000000046}') # => Excel OLE Automation WIN32OLE object.
3218  */
3219 static VALUE
3221 {
3222  VALUE svr_name;
3223  VALUE host;
3224  VALUE others;
3225  HRESULT hr;
3226  CLSID clsid;
3227  OLECHAR *pBuf;
3228  IDispatch *pDispatch;
3229  void *p;
3230  rb_secure(4);
3231  rb_call_super(0, 0);
3232  rb_scan_args(argc, argv, "11*", &svr_name, &host, &others);
3233 
3234  SafeStringValue(svr_name);
3235  if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
3236  rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
3237  StringValuePtr(svr_name));
3238  }
3239  if (!NIL_P(host)) {
3240  SafeStringValue(host);
3241  if (rb_safe_level() > 0 && OBJ_TAINTED(host)) {
3242  rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
3243  StringValuePtr(svr_name));
3244  }
3245  return ole_create_dcom(argc, argv, self);
3246  }
3247 
3248  /* get CLSID from OLE server name */
3249  pBuf = ole_vstr2wc(svr_name);
3250  hr = CLSIDFromProgID(pBuf, &clsid);
3251  if(FAILED(hr)) {
3252  hr = CLSIDFromString(pBuf, &clsid);
3253  }
3254  SysFreeString(pBuf);
3255  if(FAILED(hr)) {
3257  "unknown OLE server: `%s'",
3258  StringValuePtr(svr_name));
3259  }
3260 
3261  /* get IDispatch interface */
3262  hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
3263  &IID_IDispatch, &p);
3264  pDispatch = p;
3265  if(FAILED(hr)) {
3267  "failed to create WIN32OLE object from `%s'",
3268  StringValuePtr(svr_name));
3269  }
3270 
3271  ole_set_member(self, pDispatch);
3272  return self;
3273 }
3274 
3275 static VALUE
3276 hash2named_arg(VALUE pair, struct oleparam* pOp)
3277 {
3278  unsigned int index, i;
3279  VALUE key, value;
3280  index = pOp->dp.cNamedArgs;
3281 
3282  /*---------------------------------------------
3283  the data-type of key must be String or Symbol
3284  -----------------------------------------------*/
3285  key = rb_ary_entry(pair, 0);
3286  if(TYPE(key) != T_STRING && TYPE(key) != T_SYMBOL) {
3287  /* clear name of dispatch parameters */
3288  for(i = 1; i < index + 1; i++) {
3289  SysFreeString(pOp->pNamedArgs[i]);
3290  }
3291  /* clear dispatch parameters */
3292  for(i = 0; i < index; i++ ) {
3293  VariantClear(&(pOp->dp.rgvarg[i]));
3294  }
3295  /* raise an exception */
3296  rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
3297  }
3298  if (TYPE(key) == T_SYMBOL) {
3299  key = rb_sym_to_s(key);
3300  }
3301 
3302  /* pNamedArgs[0] is <method name>, so "index + 1" */
3303  pOp->pNamedArgs[index + 1] = ole_vstr2wc(key);
3304 
3305  value = rb_ary_entry(pair, 1);
3306  VariantInit(&(pOp->dp.rgvarg[index]));
3307  ole_val2variant(value, &(pOp->dp.rgvarg[index]));
3308 
3309  pOp->dp.cNamedArgs += 1;
3310  return Qnil;
3311 }
3312 
3313 static VALUE
3314 set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end)
3315 {
3317 
3318  Check_Type(argv, T_ARRAY);
3319  rb_ary_clear(argv);
3320  while (end-- > beg) {
3321  rb_ary_push(argv, ole_variant2val(&realargs[end]));
3322  VariantClear(&realargs[end]);
3323  }
3324  return argv;
3325 }
3326 
3327 static VALUE
3328 ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket)
3329 {
3330  LCID lcid = cWIN32OLE_lcid;
3331  struct oledata *pole;
3332  HRESULT hr;
3333  VALUE cmd;
3334  VALUE paramS;
3335  VALUE param;
3336  VALUE obj;
3337  VALUE v;
3338 
3339  BSTR wcmdname;
3340 
3341  DISPID DispID;
3342  DISPID* pDispID;
3343  EXCEPINFO excepinfo;
3344  VARIANT result;
3345  VARIANTARG* realargs = NULL;
3346  unsigned int argErr = 0;
3347  unsigned int i;
3348  unsigned int cNamedArgs;
3349  int n;
3350  struct oleparam op;
3351  struct olevariantdata *pvar;
3352  memset(&excepinfo, 0, sizeof(EXCEPINFO));
3353 
3354  VariantInit(&result);
3355 
3356  op.dp.rgvarg = NULL;
3357  op.dp.rgdispidNamedArgs = NULL;
3358  op.dp.cNamedArgs = 0;
3359  op.dp.cArgs = 0;
3360 
3361  rb_scan_args(argc, argv, "1*", &cmd, &paramS);
3362  if(TYPE(cmd) != T_STRING && TYPE(cmd) != T_SYMBOL && !is_bracket) {
3363  rb_raise(rb_eTypeError, "method is wrong type (expected String or Symbol)");
3364  }
3365  if (TYPE(cmd) == T_SYMBOL) {
3366  cmd = rb_sym_to_s(cmd);
3367  }
3368  OLEData_Get_Struct(self, pole);
3369  if(!pole->pDispatch) {
3370  rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
3371  }
3372  if (is_bracket) {
3373  DispID = DISPID_VALUE;
3374  argc += 1;
3375  rb_ary_unshift(paramS, cmd);
3376  } else {
3377  wcmdname = ole_vstr2wc(cmd);
3378  hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
3379  &wcmdname, 1, lcid, &DispID);
3380  SysFreeString(wcmdname);
3381  if(FAILED(hr)) {
3383  "unknown property or method: `%s'",
3384  StringValuePtr(cmd));
3385  }
3386  }
3387 
3388  /* pick up last argument of method */
3389  param = rb_ary_entry(paramS, argc-2);
3390 
3391  op.dp.cNamedArgs = 0;
3392 
3393  /* if last arg is hash object */
3394  if(TYPE(param) == T_HASH) {
3395  /*------------------------------------------
3396  hash object ==> named dispatch parameters
3397  --------------------------------------------*/
3398  cNamedArgs = NUM2INT(rb_funcall(param, rb_intern("length"), 0));
3399  op.dp.cArgs = cNamedArgs + argc - 2;
3400  op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
3401  op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
3402  rb_block_call(param, rb_intern("each"), 0, 0, hash2named_arg, (VALUE)&op);
3403 
3404  pDispID = ALLOCA_N(DISPID, cNamedArgs + 1);
3405  op.pNamedArgs[0] = ole_vstr2wc(cmd);
3406  hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch,
3407  &IID_NULL,
3408  op.pNamedArgs,
3409  op.dp.cNamedArgs + 1,
3410  lcid, pDispID);
3411  for(i = 0; i < op.dp.cNamedArgs + 1; i++) {
3412  SysFreeString(op.pNamedArgs[i]);
3413  op.pNamedArgs[i] = NULL;
3414  }
3415  if(FAILED(hr)) {
3416  /* clear dispatch parameters */
3417  for(i = 0; i < op.dp.cArgs; i++ ) {
3418  VariantClear(&op.dp.rgvarg[i]);
3419  }
3421  "failed to get named argument info: `%s'",
3422  StringValuePtr(cmd));
3423  }
3424  op.dp.rgdispidNamedArgs = &(pDispID[1]);
3425  }
3426  else {
3427  cNamedArgs = 0;
3428  op.dp.cArgs = argc - 1;
3429  op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
3430  if (op.dp.cArgs > 0) {
3431  op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
3432  }
3433  }
3434  /*--------------------------------------
3435  non hash args ==> dispatch parameters
3436  ----------------------------------------*/
3437  if(op.dp.cArgs > cNamedArgs) {
3438  realargs = ALLOCA_N(VARIANTARG, op.dp.cArgs-cNamedArgs+1);
3439  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
3440  n = op.dp.cArgs - i + cNamedArgs - 1;
3441  VariantInit(&realargs[n]);
3442  VariantInit(&op.dp.rgvarg[n]);
3443  param = rb_ary_entry(paramS, i-cNamedArgs);
3444  if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
3445  Data_Get_Struct(param, struct olevariantdata, pvar);
3446  VariantCopy(&op.dp.rgvarg[n], &(pvar->var));
3447  } else {
3448  ole_val2variant(param, &realargs[n]);
3449  V_VT(&op.dp.rgvarg[n]) = VT_VARIANT | VT_BYREF;
3450  V_VARIANTREF(&op.dp.rgvarg[n]) = &realargs[n];
3451  }
3452  }
3453  }
3454  /* apparent you need to call propput, you need this */
3455  if (wFlags & DISPATCH_PROPERTYPUT) {
3456  if (op.dp.cArgs == 0)
3457  ole_raise(ResultFromScode(E_INVALIDARG), eWIN32OLERuntimeError, "argument error");
3458 
3459  op.dp.cNamedArgs = 1;
3460  op.dp.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
3461  op.dp.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
3462  }
3463 
3464  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
3465  &IID_NULL, lcid, wFlags, &op.dp,
3466  &result, &excepinfo, &argErr);
3467 
3468  if (FAILED(hr)) {
3469  /* retry to call args by value */
3470  if(op.dp.cArgs >= cNamedArgs) {
3471  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
3472  n = op.dp.cArgs - i + cNamedArgs - 1;
3473  param = rb_ary_entry(paramS, i-cNamedArgs);
3474  ole_val2variant(param, &op.dp.rgvarg[n]);
3475  }
3476  if (hr == DISP_E_EXCEPTION) {
3477  ole_freeexceptinfo(&excepinfo);
3478  }
3479  memset(&excepinfo, 0, sizeof(EXCEPINFO));
3480  VariantInit(&result);
3481  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
3482  &IID_NULL, lcid, wFlags,
3483  &op.dp, &result,
3484  &excepinfo, &argErr);
3485 
3486  /* mega kludge. if a method in WORD is called and we ask
3487  * for a result when one is not returned then
3488  * hResult == DISP_E_EXCEPTION. this only happens on
3489  * functions whose DISPID > 0x8000 */
3490  if ((hr == DISP_E_EXCEPTION || hr == DISP_E_MEMBERNOTFOUND) && DispID > 0x8000) {
3491  if (hr == DISP_E_EXCEPTION) {
3492  ole_freeexceptinfo(&excepinfo);
3493  }
3494  memset(&excepinfo, 0, sizeof(EXCEPINFO));
3495  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
3496  &IID_NULL, lcid, wFlags,
3497  &op.dp, NULL,
3498  &excepinfo, &argErr);
3499 
3500  }
3501  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
3502  n = op.dp.cArgs - i + cNamedArgs - 1;
3503  VariantClear(&op.dp.rgvarg[n]);
3504  }
3505  }
3506 
3507  if (FAILED(hr)) {
3508  /* retry after converting nil to VT_EMPTY */
3509  if (op.dp.cArgs > cNamedArgs) {
3510  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
3511  n = op.dp.cArgs - i + cNamedArgs - 1;
3512  param = rb_ary_entry(paramS, i-cNamedArgs);
3513  ole_val2variant2(param, &op.dp.rgvarg[n]);
3514  }
3515  if (hr == DISP_E_EXCEPTION) {
3516  ole_freeexceptinfo(&excepinfo);
3517  }
3518  memset(&excepinfo, 0, sizeof(EXCEPINFO));
3519  VariantInit(&result);
3520  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
3521  &IID_NULL, lcid, wFlags,
3522  &op.dp, &result,
3523  &excepinfo, &argErr);
3524  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
3525  n = op.dp.cArgs - i + cNamedArgs - 1;
3526  VariantClear(&op.dp.rgvarg[n]);
3527  }
3528  }
3529  }
3530 
3531  }
3532  /* clear dispatch parameter */
3533  if(op.dp.cArgs > cNamedArgs) {
3534  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
3535  n = op.dp.cArgs - i + cNamedArgs - 1;
3536  param = rb_ary_entry(paramS, i-cNamedArgs);
3537  if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
3538  ole_val2variant(param, &realargs[n]);
3539  }
3540  }
3541  set_argv(realargs, cNamedArgs, op.dp.cArgs);
3542  }
3543  else {
3544  for(i = 0; i < op.dp.cArgs; i++) {
3545  VariantClear(&op.dp.rgvarg[i]);
3546  }
3547  }
3548 
3549  if (FAILED(hr)) {
3550  v = ole_excepinfo2msg(&excepinfo);
3551  ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `%s': )%s",
3552  StringValuePtr(cmd),
3553  StringValuePtr(v));
3554  }
3555  obj = ole_variant2val(&result);
3556  VariantClear(&result);
3557  return obj;
3558 }
3559 
3560 /*
3561  * call-seq:
3562  * WIN32OLE#invoke(method, [arg1,...]) => return value of method.
3563  *
3564  * Runs OLE method.
3565  * The first argument specifies the method name of OLE Automation object.
3566  * The others specify argument of the <i>method</i>.
3567  * If you can not execute <i>method</i> directly, then use this method instead.
3568  *
3569  * excel = WIN32OLE.new('Excel.Application')
3570  * excel.invoke('Quit') # => same as excel.Quit
3571  *
3572  */
3573 static VALUE
3575 {
3576  return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
3577 }
3578 
3579 static VALUE
3580 ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind)
3581 {
3582  HRESULT hr;
3583  struct oledata *pole;
3584  unsigned int argErr = 0;
3585  EXCEPINFO excepinfo;
3586  VARIANT result;
3587  DISPPARAMS dispParams;
3588  VARIANTARG* realargs = NULL;
3589  int i, j;
3590  VALUE obj = Qnil;
3591  VALUE tp, param;
3592  VALUE v;
3593  VARTYPE vt;
3594 
3595  Check_Type(args, T_ARRAY);
3596  Check_Type(types, T_ARRAY);
3597 
3598  memset(&excepinfo, 0, sizeof(EXCEPINFO));
3599  memset(&dispParams, 0, sizeof(DISPPARAMS));
3600  VariantInit(&result);
3601  OLEData_Get_Struct(self, pole);
3602 
3603  dispParams.cArgs = RARRAY_LEN(args);
3604  dispParams.rgvarg = ALLOCA_N(VARIANTARG, dispParams.cArgs);
3605  realargs = ALLOCA_N(VARIANTARG, dispParams.cArgs);
3606  for (i = 0, j = dispParams.cArgs - 1; i < (int)dispParams.cArgs; i++, j--)
3607  {
3608  VariantInit(&realargs[i]);
3609  VariantInit(&dispParams.rgvarg[i]);
3610  tp = rb_ary_entry(types, j);
3611  vt = (VARTYPE)FIX2INT(tp);
3612  V_VT(&dispParams.rgvarg[i]) = vt;
3613  param = rb_ary_entry(args, j);
3614  if (param == Qnil)
3615  {
3616 
3617  V_VT(&dispParams.rgvarg[i]) = V_VT(&realargs[i]) = VT_ERROR;
3618  V_ERROR(&dispParams.rgvarg[i]) = V_ERROR(&realargs[i]) = DISP_E_PARAMNOTFOUND;
3619  }
3620  else
3621  {
3622  if (vt & VT_ARRAY)
3623  {
3624  int ent;
3625  LPBYTE pb;
3626  short* ps;
3627  LPLONG pl;
3628  VARIANT* pv;
3629  CY *py;
3630  VARTYPE v;
3631  SAFEARRAYBOUND rgsabound[1];
3632  Check_Type(param, T_ARRAY);
3633  rgsabound[0].lLbound = 0;
3634  rgsabound[0].cElements = RARRAY_LEN(param);
3635  v = vt & ~(VT_ARRAY | VT_BYREF);
3636  V_ARRAY(&realargs[i]) = SafeArrayCreate(v, 1, rgsabound);
3637  V_VT(&realargs[i]) = VT_ARRAY | v;
3638  SafeArrayLock(V_ARRAY(&realargs[i]));
3639  pb = V_ARRAY(&realargs[i])->pvData;
3640  ps = V_ARRAY(&realargs[i])->pvData;
3641  pl = V_ARRAY(&realargs[i])->pvData;
3642  py = V_ARRAY(&realargs[i])->pvData;
3643  pv = V_ARRAY(&realargs[i])->pvData;
3644  for (ent = 0; ent < (int)rgsabound[0].cElements; ent++)
3645  {
3646  VARIANT velem;
3647  VALUE elem = rb_ary_entry(param, ent);
3648  ole_val2variant(elem, &velem);
3649  if (v != VT_VARIANT)
3650  {
3651  VariantChangeTypeEx(&velem, &velem,
3652  cWIN32OLE_lcid, 0, v);
3653  }
3654  switch (v)
3655  {
3656  /* 128 bits */
3657  case VT_VARIANT:
3658  *pv++ = velem;
3659  break;
3660  /* 64 bits */
3661  case VT_R8:
3662  case VT_CY:
3663  case VT_DATE:
3664  *py++ = V_CY(&velem);
3665  break;
3666  /* 16 bits */
3667  case VT_BOOL:
3668  case VT_I2:
3669  case VT_UI2:
3670  *ps++ = V_I2(&velem);
3671  break;
3672  /* 8 bites */
3673  case VT_UI1:
3674  case VT_I1:
3675  *pb++ = V_UI1(&velem);
3676  break;
3677  /* 32 bits */
3678  default:
3679  *pl++ = V_I4(&velem);
3680  break;
3681  }
3682  }
3683  SafeArrayUnlock(V_ARRAY(&realargs[i]));
3684  }
3685  else
3686  {
3687  ole_val2variant(param, &realargs[i]);
3688  if ((vt & (~VT_BYREF)) != VT_VARIANT)
3689  {
3690  hr = VariantChangeTypeEx(&realargs[i], &realargs[i],
3691  cWIN32OLE_lcid, 0,
3692  (VARTYPE)(vt & (~VT_BYREF)));
3693  if (hr != S_OK)
3694  {
3695  rb_raise(rb_eTypeError, "not valid value");
3696  }
3697  }
3698  }
3699  if ((vt & VT_BYREF) || vt == VT_VARIANT)
3700  {
3701  if (vt == VT_VARIANT)
3702  V_VT(&dispParams.rgvarg[i]) = VT_VARIANT | VT_BYREF;
3703  switch (vt & (~VT_BYREF))
3704  {
3705  /* 128 bits */
3706  case VT_VARIANT:
3707  V_VARIANTREF(&dispParams.rgvarg[i]) = &realargs[i];
3708  break;
3709  /* 64 bits */
3710  case VT_R8:
3711  case VT_CY:
3712  case VT_DATE:
3713  V_CYREF(&dispParams.rgvarg[i]) = &V_CY(&realargs[i]);
3714  break;
3715  /* 16 bits */
3716  case VT_BOOL:
3717  case VT_I2:
3718  case VT_UI2:
3719  V_I2REF(&dispParams.rgvarg[i]) = &V_I2(&realargs[i]);
3720  break;
3721  /* 8 bites */
3722  case VT_UI1:
3723  case VT_I1:
3724  V_UI1REF(&dispParams.rgvarg[i]) = &V_UI1(&realargs[i]);
3725  break;
3726  /* 32 bits */
3727  default:
3728  V_I4REF(&dispParams.rgvarg[i]) = &V_I4(&realargs[i]);
3729  break;
3730  }
3731  }
3732  else
3733  {
3734  /* copy 64 bits of data */
3735  V_CY(&dispParams.rgvarg[i]) = V_CY(&realargs[i]);
3736  }
3737  }
3738  }
3739 
3740  if (dispkind & DISPATCH_PROPERTYPUT) {
3741  dispParams.cNamedArgs = 1;
3742  dispParams.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
3743  dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
3744  }
3745 
3746  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, NUM2INT(dispid),
3747  &IID_NULL, cWIN32OLE_lcid,
3748  dispkind,
3749  &dispParams, &result,
3750  &excepinfo, &argErr);
3751 
3752  if (FAILED(hr)) {
3753  v = ole_excepinfo2msg(&excepinfo);
3754  ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `<dispatch id:%d>': )%s",
3755  NUM2INT(dispid),
3756  StringValuePtr(v));
3757  }
3758 
3759  /* clear dispatch parameter */
3760  if(dispParams.cArgs > 0) {
3761  set_argv(realargs, 0, dispParams.cArgs);
3762  }
3763 
3764  obj = ole_variant2val(&result);
3765  VariantClear(&result);
3766  return obj;
3767 }
3768 
3769 /*
3770  * call-seq:
3771  * WIN32OLE#_invoke(dispid, args, types)
3772  *
3773  * Runs the early binding method.
3774  * The 1st argument specifies dispatch ID,
3775  * the 2nd argument specifies the array of arguments,
3776  * the 3rd argument specifies the array of the type of arguments.
3777  *
3778  * excel = WIN32OLE.new('Excel.Application')
3779  * excel._invoke(302, [], []) # same effect as excel.Quit
3780  */
3781 static VALUE
3782 fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3783 {
3784  return ole_invoke2(self, dispid, args, types, DISPATCH_METHOD);
3785 }
3786 
3787 /*
3788  * call-seq:
3789  * WIN32OLE#_getproperty(dispid, args, types)
3790  *
3791  * Runs the early binding method to get property.
3792  * The 1st argument specifies dispatch ID,
3793  * the 2nd argument specifies the array of arguments,
3794  * the 3rd argument specifies the array of the type of arguments.
3795  *
3796  * excel = WIN32OLE.new('Excel.Application')
3797  * puts excel._getproperty(558, [], []) # same effect as puts excel.visible
3798  */
3799 static VALUE
3801 {
3802  return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYGET);
3803 }
3804 
3805 /*
3806  * call-seq:
3807  * WIN32OLE#_setproperty(dispid, args, types)
3808  *
3809  * Runs the early binding method to set property.
3810  * The 1st argument specifies dispatch ID,
3811  * the 2nd argument specifies the array of arguments,
3812  * the 3rd argument specifies the array of the type of arguments.
3813  *
3814  * excel = WIN32OLE.new('Excel.Application')
3815  * excel._setproperty(558, [true], [WIN32OLE::VARIANT::VT_BOOL]) # same effect as excel.visible = true
3816  */
3817 static VALUE
3819 {
3820  return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYPUT);
3821 }
3822 
3823 /*
3824  * call-seq:
3825  * WIN32OLE[a1, a2, ...]=val
3826  *
3827  * Sets the value to WIN32OLE object specified by a1, a2, ...
3828  *
3829  * dict = WIN32OLE.new('Scripting.Dictionary')
3830  * dict.add('ruby', 'RUBY')
3831  * dict['ruby'] = 'Ruby'
3832  * puts dict['ruby'] # => 'Ruby'
3833  *
3834  * Remark: You can not use this method to set the property value.
3835  *
3836  * excel = WIN32OLE.new('Excel.Application')
3837  * # excel['Visible'] = true # This is error !!!
3838  * excel.Visible = true # You should to use this style to set the property.
3839  *
3840  */
3841 static VALUE
3843 {
3844  return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, TRUE);
3845 }
3846 
3847 /*
3848  * call-seq:
3849  * WIN32OLE.setproperty('property', [arg1, arg2,...] val)
3850  *
3851  * Sets property of OLE object.
3852  * When you want to set property with argument, you can use this method.
3853  *
3854  * excel = WIN32OLE.new('Excel.Application')
3855  * excel.Visible = true
3856  * book = excel.workbooks.add
3857  * sheet = book.worksheets(1)
3858  * sheet.setproperty('Cells', 1, 2, 10) # => The B1 cell value is 10.
3859  */
3860 static VALUE
3862 {
3863  return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, FALSE);
3864 }
3865 
3866 /*
3867  * call-seq:
3868  * WIN32OLE[a1,a2,...]
3869  *
3870  * Returns the value of Collection specified by a1, a2,....
3871  *
3872  * dict = WIN32OLE.new('Scripting.Dictionary')
3873  * dict.add('ruby', 'Ruby')
3874  * puts dict['ruby'] # => 'Ruby' (same as `puts dict.item('ruby')')
3875  *
3876  * Remark: You can not use this method to get the property.
3877  * excel = WIN32OLE.new('Excel.Application')
3878  * # puts excel['Visible'] This is error !!!
3879  * puts excel.Visible # You should to use this style to get the property.
3880  *
3881  */
3882 static VALUE
3884 {
3885  return ole_invoke(argc, argv, self, DISPATCH_PROPERTYGET, TRUE);
3886 }
3887 
3888 static VALUE
3889 ole_propertyput(VALUE self, VALUE property, VALUE value)
3890 {
3891  struct oledata *pole;
3892  unsigned argErr;
3893  unsigned int index;
3894  HRESULT hr;
3895  EXCEPINFO excepinfo;
3896  DISPID dispID = DISPID_VALUE;
3897  DISPID dispIDParam = DISPID_PROPERTYPUT;
3898  USHORT wFlags = DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF;
3899  DISPPARAMS dispParams;
3900  VARIANTARG propertyValue[2];
3901  OLECHAR* pBuf[1];
3902  VALUE v;
3903  LCID lcid = cWIN32OLE_lcid;
3904  dispParams.rgdispidNamedArgs = &dispIDParam;
3905  dispParams.rgvarg = propertyValue;
3906  dispParams.cNamedArgs = 1;
3907  dispParams.cArgs = 1;
3908 
3909  VariantInit(&propertyValue[0]);
3910  VariantInit(&propertyValue[1]);
3911  memset(&excepinfo, 0, sizeof(excepinfo));
3912 
3913  OLEData_Get_Struct(self, pole);
3914 
3915  /* get ID from property name */
3916  pBuf[0] = ole_vstr2wc(property);
3917  hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, &IID_NULL,
3918  pBuf, 1, lcid, &dispID);
3919  SysFreeString(pBuf[0]);
3920  pBuf[0] = NULL;
3921 
3922  if(FAILED(hr)) {
3924  "unknown property or method: `%s'",
3925  StringValuePtr(property));
3926  }
3927  /* set property value */
3928  ole_val2variant(value, &propertyValue[0]);
3929  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, dispID, &IID_NULL,
3930  lcid, wFlags, &dispParams,
3931  NULL, &excepinfo, &argErr);
3932 
3933  for(index = 0; index < dispParams.cArgs; ++index) {
3934  VariantClear(&propertyValue[index]);
3935  }
3936  if (FAILED(hr)) {
3937  v = ole_excepinfo2msg(&excepinfo);
3938  ole_raise(hr, eWIN32OLERuntimeError, "(in setting property `%s': )%s",
3939  StringValuePtr(property),
3940  StringValuePtr(v));
3941  }
3942  return Qnil;
3943 }
3944 
3945 /*
3946  * call-seq:
3947  * WIN32OLE#ole_free
3948  *
3949  * invokes Release method of Dispatch interface of WIN32OLE object.
3950  * Usually, you do not need to call this method because Release method
3951  * called automatically when WIN32OLE object garbaged.
3952  *
3953  */
3954 static VALUE
3956 {
3957  struct oledata *pole;
3958  rb_secure(4);
3959  OLEData_Get_Struct(self, pole);
3960  OLE_FREE(pole->pDispatch);
3961  pole->pDispatch = NULL;
3962  return Qnil;
3963 }
3964 
3965 static VALUE
3967 {
3968  VARIANT variant;
3969  VALUE obj = Qnil;
3970  IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
3971  VariantInit(&variant);
3972  while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) {
3973  obj = ole_variant2val(&variant);
3974  VariantClear(&variant);
3975  VariantInit(&variant);
3976  rb_yield(obj);
3977  }
3978  return Qnil;
3979 }
3980 
3981 static VALUE
3983 {
3984  IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
3985  OLE_RELEASE(pEnum);
3986  return Qnil;
3987 }
3988 
3989 /*
3990  * call-seq:
3991  * WIN32OLE#each {|i|...}
3992  *
3993  * Iterates over each item of OLE collection which has IEnumVARIANT interface.
3994  *
3995  * excel = WIN32OLE.new('Excel.Application')
3996  * book = excel.workbooks.add
3997  * sheets = book.worksheets(1)
3998  * cells = sheets.cells("A1:A5")
3999  * cells.each do |cell|
4000  * cell.value = 10
4001  * end
4002  */
4003 static VALUE
4005 {
4006  LCID lcid = cWIN32OLE_lcid;
4007 
4008  struct oledata *pole;
4009 
4010  unsigned int argErr;
4011  EXCEPINFO excepinfo;
4012  DISPPARAMS dispParams;
4013  VARIANT result;
4014  HRESULT hr;
4015  IEnumVARIANT *pEnum = NULL;
4016  void *p;
4017 
4018  RETURN_ENUMERATOR(self, 0, 0);
4019 
4020  VariantInit(&result);
4021  dispParams.rgvarg = NULL;
4022  dispParams.rgdispidNamedArgs = NULL;
4023  dispParams.cNamedArgs = 0;
4024  dispParams.cArgs = 0;
4025  memset(&excepinfo, 0, sizeof(excepinfo));
4026 
4027  OLEData_Get_Struct(self, pole);
4028  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DISPID_NEWENUM,
4029  &IID_NULL, lcid,
4030  DISPATCH_METHOD | DISPATCH_PROPERTYGET,
4031  &dispParams, &result,
4032  &excepinfo, &argErr);
4033 
4034  if (FAILED(hr)) {
4035  VariantClear(&result);
4036  ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface");
4037  }
4038 
4039  if (V_VT(&result) == VT_UNKNOWN) {
4040  hr = V_UNKNOWN(&result)->lpVtbl->QueryInterface(V_UNKNOWN(&result),
4041  &IID_IEnumVARIANT,
4042  &p);
4043  pEnum = p;
4044  } else if (V_VT(&result) == VT_DISPATCH) {
4045  hr = V_DISPATCH(&result)->lpVtbl->QueryInterface(V_DISPATCH(&result),
4046  &IID_IEnumVARIANT,
4047  &p);
4048  pEnum = p;
4049  }
4050  if (FAILED(hr) || !pEnum) {
4051  VariantClear(&result);
4052  ole_raise(hr, rb_eRuntimeError, "failed to get IEnum Interface");
4053  }
4054 
4055  VariantClear(&result);
4056  rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum);
4057  return Qnil;
4058 }
4059 
4060 /*
4061  * call-seq:
4062  * WIN32OLE#method_missing(id [,arg1, arg2, ...])
4063  *
4064  * Calls WIN32OLE#invoke method.
4065  */
4066 static VALUE
4068 {
4069  ID id;
4070  const char* mname;
4071  int n;
4072  id = rb_to_id(argv[0]);
4073  mname = rb_id2name(id);
4074  if(!mname) {
4075  rb_raise(rb_eRuntimeError, "fail: unknown method or property");
4076  }
4077  n = strlen(mname);
4078  if(mname[n-1] == '=') {
4079  argv[0] = rb_enc_str_new(mname, n-1, cWIN32OLE_enc);
4080 
4081  return ole_propertyput(self, argv[0], argv[1]);
4082  }
4083  else {
4084  argv[0] = rb_enc_str_new(mname, n, cWIN32OLE_enc);
4085  return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
4086  }
4087 }
4088 
4089 static VALUE
4090 ole_method_sub(VALUE self, ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE name)
4091 {
4092  HRESULT hr;
4093  TYPEATTR *pTypeAttr;
4094  BSTR bstr;
4095  FUNCDESC *pFuncDesc;
4096  WORD i;
4097  VALUE fname;
4098  VALUE method = Qnil;
4099  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4100  if (FAILED(hr)) {
4101  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
4102  }
4103  for(i = 0; i < pTypeAttr->cFuncs && method == Qnil; i++) {
4104  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, i, &pFuncDesc);
4105  if (FAILED(hr))
4106  continue;
4107 
4108  hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
4109  &bstr, NULL, NULL, NULL);
4110  if (FAILED(hr)) {
4111  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4112  continue;
4113  }
4114  fname = WC2VSTR(bstr);
4115  if (strcasecmp(StringValuePtr(name), StringValuePtr(fname)) == 0) {
4116  olemethod_set_member(self, pTypeInfo, pOwnerTypeInfo, i, fname);
4117  method = self;
4118  }
4119  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4120  pFuncDesc=NULL;
4121  }
4122  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
4123  return method;
4124 }
4125 
4126 static VALUE
4127 olemethod_from_typeinfo(VALUE self, ITypeInfo *pTypeInfo, VALUE name)
4128 {
4129  HRESULT hr;
4130  TYPEATTR *pTypeAttr;
4131  WORD i;
4132  HREFTYPE href;
4133  ITypeInfo *pRefTypeInfo;
4134  VALUE method = Qnil;
4135  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4136  if (FAILED(hr)) {
4137  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
4138  }
4139  method = ole_method_sub(self, 0, pTypeInfo, name);
4140  if (method != Qnil) {
4141  return method;
4142  }
4143  for(i=0; i < pTypeAttr->cImplTypes && method == Qnil; i++){
4144  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
4145  if(FAILED(hr))
4146  continue;
4147  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
4148  if (FAILED(hr))
4149  continue;
4150  method = ole_method_sub(self, pTypeInfo, pRefTypeInfo, name);
4151  OLE_RELEASE(pRefTypeInfo);
4152  }
4153  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
4154  return method;
4155 }
4156 
4157 static VALUE
4158 ole_methods_sub(ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE methods, int mask)
4159 {
4160  HRESULT hr;
4161  TYPEATTR *pTypeAttr;
4162  BSTR bstr;
4163  char *pstr;
4164  FUNCDESC *pFuncDesc;
4165  VALUE method;
4166  WORD i;
4167  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4168  if (FAILED(hr)) {
4169  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
4170  }
4171  for(i = 0; i < pTypeAttr->cFuncs; i++) {
4172  pstr = NULL;
4173  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, i, &pFuncDesc);
4174  if (FAILED(hr))
4175  continue;
4176 
4177  hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
4178  &bstr, NULL, NULL, NULL);
4179  if (FAILED(hr)) {
4180  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4181  continue;
4182  }
4183  if(pFuncDesc->invkind & mask) {
4185  olemethod_set_member(method, pTypeInfo, pOwnerTypeInfo,
4186  i, WC2VSTR(bstr));
4187  rb_ary_push(methods, method);
4188  }
4189  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4190  pFuncDesc=NULL;
4191  }
4192  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
4193 
4194  return methods;
4195 }
4196 
4197 static VALUE
4198 ole_methods_from_typeinfo(ITypeInfo *pTypeInfo, int mask)
4199 {
4200  HRESULT hr;
4201  TYPEATTR *pTypeAttr;
4202  WORD i;
4203  HREFTYPE href;
4204  ITypeInfo *pRefTypeInfo;
4205  VALUE methods = rb_ary_new();
4206  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4207  if (FAILED(hr)) {
4208  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
4209  }
4210 
4211  ole_methods_sub(0, pTypeInfo, methods, mask);
4212  for(i=0; i < pTypeAttr->cImplTypes; i++){
4213  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
4214  if(FAILED(hr))
4215  continue;
4216  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
4217  if (FAILED(hr))
4218  continue;
4219  ole_methods_sub(pTypeInfo, pRefTypeInfo, methods, mask);
4220  OLE_RELEASE(pRefTypeInfo);
4221  }
4222  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
4223  return methods;
4224 }
4225 
4226 static HRESULT
4227 typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti)
4228 {
4229  ITypeInfo *pTypeInfo;
4230  ITypeLib *pTypeLib;
4231  BSTR bstr;
4232  VALUE type;
4233  UINT i;
4234  UINT count;
4235  LCID lcid = cWIN32OLE_lcid;
4236  HRESULT hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
4237  0, lcid, &pTypeInfo);
4238  if(FAILED(hr)) {
4239  ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
4240  }
4241  hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo,
4242  -1,
4243  &bstr,
4244  NULL, NULL, NULL);
4245  type = WC2VSTR(bstr);
4246  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
4247  OLE_RELEASE(pTypeInfo);
4248  if (FAILED(hr)) {
4249  ole_raise(hr, rb_eRuntimeError, "failed to GetContainingTypeLib");
4250  }
4251  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
4252  for (i = 0; i < count; i++) {
4253  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
4254  &bstr, NULL, NULL, NULL);
4255  if (SUCCEEDED(hr) && rb_str_cmp(WC2VSTR(bstr), type) == 0) {
4256  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
4257  if (SUCCEEDED(hr)) {
4258  *ppti = pTypeInfo;
4259  break;
4260  }
4261  }
4262  }
4263  OLE_RELEASE(pTypeLib);
4264  return hr;
4265 }
4266 
4267 static VALUE
4268 ole_methods(VALUE self, int mask)
4269 {
4270  ITypeInfo *pTypeInfo;
4271  HRESULT hr;
4272  VALUE methods;
4273  struct oledata *pole;
4274 
4275  OLEData_Get_Struct(self, pole);
4276  methods = rb_ary_new();
4277 
4278  hr = typeinfo_from_ole(pole, &pTypeInfo);
4279  if(FAILED(hr))
4280  return methods;
4281  rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask));
4282  OLE_RELEASE(pTypeInfo);
4283  return methods;
4284 }
4285 
4286 /*
4287  * call-seq:
4288  * WIN32OLE#ole_methods
4289  *
4290  * Returns the array of WIN32OLE_METHOD object.
4291  * The element is OLE method of WIN32OLE object.
4292  *
4293  * excel = WIN32OLE.new('Excel.Application')
4294  * methods = excel.ole_methods
4295  *
4296  */
4297 static VALUE
4299 {
4300  return ole_methods( self, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
4301 }
4302 
4303 /*
4304  * call-seq:
4305  * WIN32OLE#ole_get_methods
4306  *
4307  * Returns the array of WIN32OLE_METHOD object .
4308  * The element of the array is property (gettable) of WIN32OLE object.
4309  *
4310  * excel = WIN32OLE.new('Excel.Application')
4311  * properties = excel.ole_get_methods
4312  */
4313 static VALUE
4315 {
4316  return ole_methods( self, INVOKE_PROPERTYGET);
4317 }
4318 
4319 /*
4320  * call-seq:
4321  * WIN32OLE#ole_put_methods
4322  *
4323  * Returns the array of WIN32OLE_METHOD object .
4324  * The element of the array is property (settable) of WIN32OLE object.
4325  *
4326  * excel = WIN32OLE.new('Excel.Application')
4327  * properties = excel.ole_put_methods
4328  */
4329 static VALUE
4331 {
4332  return ole_methods( self, INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF);
4333 }
4334 
4335 /*
4336  * call-seq:
4337  * WIN32OLE#ole_func_methods
4338  *
4339  * Returns the array of WIN32OLE_METHOD object .
4340  * The element of the array is property (settable) of WIN32OLE object.
4341  *
4342  * excel = WIN32OLE.new('Excel.Application')
4343  * properties = excel.ole_func_methods
4344  *
4345  */
4346 static VALUE
4348 {
4349  return ole_methods( self, INVOKE_FUNC);
4350 }
4351 
4352 static VALUE
4353 ole_type_from_itypeinfo(ITypeInfo *pTypeInfo)
4354 {
4355  ITypeLib *pTypeLib;
4356  VALUE type = Qnil;
4357  HRESULT hr;
4358  unsigned int index;
4359  BSTR bstr;
4360 
4361  hr = pTypeInfo->lpVtbl->GetContainingTypeLib( pTypeInfo, &pTypeLib, &index );
4362  if(FAILED(hr)) {
4363  return Qnil;
4364  }
4365  hr = pTypeLib->lpVtbl->GetDocumentation( pTypeLib, index,
4366  &bstr, NULL, NULL, NULL);
4367  OLE_RELEASE(pTypeLib);
4368  if (FAILED(hr)) {
4369  return Qnil;
4370  }
4372  oletype_set_member(type, pTypeInfo, WC2VSTR(bstr));
4373  return type;
4374 }
4375 
4376 /*
4377  * call-seq:
4378  * WIN32OLE#ole_type
4379  *
4380  * Returns WIN32OLE_TYPE object.
4381  *
4382  * excel = WIN32OLE.new('Excel.Application')
4383  * tobj = excel.ole_type
4384  */
4385 static VALUE
4387 {
4388  ITypeInfo *pTypeInfo;
4389  HRESULT hr;
4390  struct oledata *pole;
4391  LCID lcid = cWIN32OLE_lcid;
4392  VALUE type = Qnil;
4393 
4394  OLEData_Get_Struct(self, pole);
4395 
4396  hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo );
4397  if(FAILED(hr)) {
4398  ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
4399  }
4400  type = ole_type_from_itypeinfo(pTypeInfo);
4401  OLE_RELEASE(pTypeInfo);
4402  if (type == Qnil) {
4403  rb_raise(rb_eRuntimeError, "failed to create WIN32OLE_TYPE obj from ITypeInfo");
4404  }
4405  return type;
4406 }
4407 
4408 static VALUE
4409 ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo)
4410 {
4411  HRESULT hr;
4412  ITypeLib *pTypeLib;
4413  unsigned int index;
4414  VALUE retval = Qnil;
4415 
4416  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
4417  if(FAILED(hr)) {
4418  return Qnil;
4419  }
4420  retval = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("allocate"), 0);
4421  oletypelib_set_member(retval, pTypeLib);
4422  return retval;
4423 }
4424 
4425 /*
4426  * call-seq:
4427  * WIN32OLE#ole_typelib -> The WIN32OLE_TYPELIB object
4428  *
4429  * Returns the WIN32OLE_TYPELIB object. The object represents the
4430  * type library which contains the WIN32OLE object.
4431  *
4432  * excel = WIN32OLE.new('Excel.Application')
4433  * tlib = excel.ole_typelib
4434  * puts tlib.name # -> 'Microsoft Excel 9.0 Object Library'
4435  */
4436 static VALUE
4438 {
4439  struct oledata *pole;
4440  HRESULT hr;
4441  ITypeInfo *pTypeInfo;
4442  LCID lcid = cWIN32OLE_lcid;
4443  VALUE vtlib = Qnil;
4444 
4445  OLEData_Get_Struct(self, pole);
4446  hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
4447  0, lcid, &pTypeInfo);
4448  if(FAILED(hr)) {
4449  ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
4450  }
4451  vtlib = ole_typelib_from_itypeinfo(pTypeInfo);
4452  OLE_RELEASE(pTypeInfo);
4453  if (vtlib == Qnil) {
4454  rb_raise(rb_eRuntimeError, "failed to get type library info.");
4455  }
4456  return vtlib;
4457 }
4458 
4459 /*
4460  * call-seq:
4461  * WIN32OLE#ole_query_interface(iid) -> WIN32OLE object
4462  *
4463  * Returns WIN32OLE object for a specific dispatch or dual
4464  * interface specified by iid.
4465  *
4466  * ie = WIN32OLE.new('InternetExplorer.Application')
4467  * ie_web_app = ie.ole_query_interface('{0002DF05-0000-0000-C000-000000000046}') # => WIN32OLE object for dispinterface IWebBrowserApp
4468  */
4469 static VALUE
4471 {
4472  HRESULT hr;
4473  OLECHAR *pBuf;
4474  IID iid;
4475  struct oledata *pole;
4476  IDispatch *pDispatch;
4477  void *p;
4478 
4479  pBuf = ole_vstr2wc(str_iid);
4480  hr = CLSIDFromString(pBuf, &iid);
4481  SysFreeString(pBuf);
4482  if(FAILED(hr)) {
4484  "invalid iid: `%s'",
4485  StringValuePtr(str_iid));
4486  }
4487 
4488  OLEData_Get_Struct(self, pole);
4489  if(!pole->pDispatch) {
4490  rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
4491  }
4492 
4493  hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &iid,
4494  &p);
4495  if(FAILED(hr)) {
4497  "failed to get interface `%s'",
4498  StringValuePtr(str_iid));
4499  }
4500 
4501  pDispatch = p;
4502  return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
4503 }
4504 
4505 /*
4506  * call-seq:
4507  * WIN32OLE#ole_respond_to?(method) -> true or false
4508  *
4509  * Returns true when OLE object has OLE method, otherwise returns false.
4510  *
4511  * ie = WIN32OLE.new('InternetExplorer.Application')
4512  * ie.ole_respond_to?("gohome") => true
4513  */
4514 static VALUE
4516 {
4517  struct oledata *pole;
4518  BSTR wcmdname;
4519  DISPID DispID;
4520  HRESULT hr;
4521  rb_secure(4);
4522  if(TYPE(method) != T_STRING && TYPE(method) != T_SYMBOL) {
4523  rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
4524  }
4525  if (TYPE(method) == T_SYMBOL) {
4526  method = rb_sym_to_s(method);
4527  }
4528  OLEData_Get_Struct(self, pole);
4529  wcmdname = ole_vstr2wc(method);
4530  hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
4531  &wcmdname, 1, cWIN32OLE_lcid, &DispID);
4532  SysFreeString(wcmdname);
4533  return SUCCEEDED(hr) ? Qtrue : Qfalse;
4534 }
4535 
4536 static HRESULT
4537 ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile)
4538 {
4539  HRESULT hr;
4540  ITypeLib *pTypeLib;
4541  UINT i;
4542 
4543  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
4544  if (FAILED(hr)) {
4545  return hr;
4546  }
4547 
4548  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
4549  name, helpstr,
4550  helpcontext, helpfile);
4551  if (FAILED(hr)) {
4552  OLE_RELEASE(pTypeLib);
4553  return hr;
4554  }
4555  OLE_RELEASE(pTypeLib);
4556  return hr;
4557 }
4558 
4559 static VALUE
4560 ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
4561 {
4562  HRESULT hr;
4563  BSTR bstr;
4564  ITypeInfo *pRefTypeInfo;
4565  VALUE type = Qnil;
4566 
4567  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
4568  V_UNION1(pTypeDesc, hreftype),
4569  &pRefTypeInfo);
4570  if(FAILED(hr))
4571  return Qnil;
4572  hr = ole_docinfo_from_type(pRefTypeInfo, &bstr, NULL, NULL, NULL);
4573  if(FAILED(hr)) {
4574  OLE_RELEASE(pRefTypeInfo);
4575  return Qnil;
4576  }
4577  OLE_RELEASE(pRefTypeInfo);
4578  type = WC2VSTR(bstr);
4579  if(typedetails != Qnil)
4580  rb_ary_push(typedetails, type);
4581  return type;
4582 }
4583 
4584 static VALUE
4585 ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
4586 {
4587  TYPEDESC *p = pTypeDesc;
4588  VALUE type = rb_str_new2("");
4589 
4590  if (p->vt == VT_PTR || p->vt == VT_SAFEARRAY) {
4591  p = V_UNION1(p, lptdesc);
4592  type = ole_typedesc2val(pTypeInfo, p, typedetails);
4593  }
4594  return type;
4595 }
4596 
4597 static VALUE
4598 ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
4599 {
4600  VALUE str;
4601  VALUE typestr = Qnil;
4602  switch(pTypeDesc->vt) {
4603  case VT_I2:
4604  typestr = rb_str_new2("I2");
4605  break;
4606  case VT_I4:
4607  typestr = rb_str_new2("I4");
4608  break;
4609  case VT_R4:
4610  typestr = rb_str_new2("R4");
4611  break;
4612  case VT_R8:
4613  typestr = rb_str_new2("R8");
4614  break;
4615  case VT_CY:
4616  typestr = rb_str_new2("CY");
4617  break;
4618  case VT_DATE:
4619  typestr = rb_str_new2("DATE");
4620  break;
4621  case VT_BSTR:
4622  typestr = rb_str_new2("BSTR");
4623  break;
4624  case VT_BOOL:
4625  typestr = rb_str_new2("BOOL");
4626  break;
4627  case VT_VARIANT:
4628  typestr = rb_str_new2("VARIANT");
4629  break;
4630  case VT_DECIMAL:
4631  typestr = rb_str_new2("DECIMAL");
4632  break;
4633  case VT_I1:
4634  typestr = rb_str_new2("I1");
4635  break;
4636  case VT_UI1:
4637  typestr = rb_str_new2("UI1");
4638  break;
4639  case VT_UI2:
4640  typestr = rb_str_new2("UI2");
4641  break;
4642  case VT_UI4:
4643  typestr = rb_str_new2("UI4");
4644  break;
4645 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
4646  case VT_I8:
4647  typestr = rb_str_new2("I8");
4648  break;
4649  case VT_UI8:
4650  typestr = rb_str_new2("UI8");
4651  break;
4652 #endif
4653  case VT_INT:
4654  typestr = rb_str_new2("INT");
4655  break;
4656  case VT_UINT:
4657  typestr = rb_str_new2("UINT");
4658  break;
4659  case VT_VOID:
4660  typestr = rb_str_new2("VOID");
4661  break;
4662  case VT_HRESULT:
4663  typestr = rb_str_new2("HRESULT");
4664  break;
4665  case VT_PTR:
4666  typestr = rb_str_new2("PTR");
4667  if(typedetails != Qnil)
4668  rb_ary_push(typedetails, typestr);
4669  return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
4670  case VT_SAFEARRAY:
4671  typestr = rb_str_new2("SAFEARRAY");
4672  if(typedetails != Qnil)
4673  rb_ary_push(typedetails, typestr);
4674  return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
4675  case VT_CARRAY:
4676  typestr = rb_str_new2("CARRAY");
4677  break;
4678  case VT_USERDEFINED:
4679  typestr = rb_str_new2("USERDEFINED");
4680  if (typedetails != Qnil)
4681  rb_ary_push(typedetails, typestr);
4682  str = ole_usertype2val(pTypeInfo, pTypeDesc, typedetails);
4683  if (str != Qnil) {
4684  return str;
4685  }
4686  return typestr;
4687  case VT_UNKNOWN:
4688  typestr = rb_str_new2("UNKNOWN");
4689  break;
4690  case VT_DISPATCH:
4691  typestr = rb_str_new2("DISPATCH");
4692  break;
4693  case VT_ERROR:
4694  typestr = rb_str_new2("ERROR");
4695  break;
4696  case VT_LPWSTR:
4697  typestr = rb_str_new2("LPWSTR");
4698  break;
4699  case VT_LPSTR:
4700  typestr = rb_str_new2("LPSTR");
4701  break;
4702  default:
4703  typestr = rb_str_new2("Unknown Type ");
4704  rb_str_concat(typestr, rb_fix2str(INT2FIX(pTypeDesc->vt), 10));
4705  break;
4706  }
4707  if (typedetails != Qnil)
4708  rb_ary_push(typedetails, typestr);
4709  return typestr;
4710 }
4711 
4712 /*
4713  * call-seq:
4714  * WIN32OLE#ole_method_help(method)
4715  *
4716  * Returns WIN32OLE_METHOD object corresponding with method
4717  * specified by 1st argument.
4718  *
4719  * excel = WIN32OLE.new('Excel.Application')
4720  * method = excel.ole_method_help('Quit')
4721  *
4722  */
4723 static VALUE
4725 {
4726  ITypeInfo *pTypeInfo;
4727  HRESULT hr;
4728  struct oledata *pole;
4729  VALUE method, obj;
4730 
4731  SafeStringValue(cmdname);
4732  OLEData_Get_Struct(self, pole);
4733  hr = typeinfo_from_ole(pole, &pTypeInfo);
4734  if(FAILED(hr))
4735  ole_raise(hr, rb_eRuntimeError, "failed to get ITypeInfo");
4737  obj = olemethod_from_typeinfo(method, pTypeInfo, cmdname);
4738  OLE_RELEASE(pTypeInfo);
4739  if (obj == Qnil)
4740  rb_raise(eWIN32OLERuntimeError, "not found %s",
4741  StringValuePtr(cmdname));
4742  return obj;
4743 }
4744 
4745 /*
4746  * call-seq:
4747  * WIN32OLE#ole_activex_initialize() -> Qnil
4748  *
4749  * Initialize WIN32OLE object(ActiveX Control) by calling
4750  * IPersistMemory::InitNew.
4751  *
4752  * Before calling OLE method, some kind of the ActiveX controls
4753  * created with MFC should be initialized by calling
4754  * IPersistXXX::InitNew.
4755  *
4756  * If and only if you received the exception "HRESULT error code:
4757  * 0x8000ffff catastrophic failure", try this method before
4758  * invoking any ole_method.
4759  *
4760  * obj = WIN32OLE.new("ProgID_or_GUID_of_ActiveX_Control")
4761  * obj.ole_activex_initialize
4762  * obj.method(...)
4763  *
4764  */
4765 static VALUE
4767 {
4768  struct oledata *pole;
4769  IPersistMemory *pPersistMemory;
4770  void *p;
4771 
4772  HRESULT hr = S_OK;
4773 
4774  OLEData_Get_Struct(self, pole);
4775 
4776  hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p);
4777  pPersistMemory = p;
4778  if (SUCCEEDED(hr)) {
4779  hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory);
4780  OLE_RELEASE(pPersistMemory);
4781  if (SUCCEEDED(hr)) {
4782  return Qnil;
4783  }
4784  }
4785 
4786  if (FAILED(hr)) {
4787  ole_raise(hr, eWIN32OLERuntimeError, "fail to initialize ActiveX control");
4788  }
4789 
4790  return Qnil;
4791 }
4792 
4793 /*
4794  * call-seq:
4795  * WIN32OLE_TYPE.ole_classes(typelib)
4796  *
4797  * Returns array of WIN32OLE_TYPE objects defined by the <i>typelib</i> type library.
4798  * This method will be OBSOLETE. Use WIN32OLE_TYPELIB.new(typelib).ole_classes instead.
4799  */
4800 static VALUE
4802 {
4803  VALUE obj;
4804 
4805  /*
4806  rb_warn("%s is obsolete; use %s instead.",
4807  "WIN32OLE_TYPE.ole_classes",
4808  "WIN32OLE_TYPELIB.new(typelib).ole_types");
4809  */
4810  obj = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("new"), 1, typelib);
4811  return rb_funcall(obj, rb_intern("ole_types"), 0);
4812 }
4813 
4814 /*
4815  * call-seq:
4816  * WIN32OLE_TYPE.typelibs
4817  *
4818  * Returns array of type libraries.
4819  * This method will be OBSOLETE. Use WIN32OLE_TYPELIB.typelibs.collect{|t| t.name} instead.
4820  *
4821  */
4822 static VALUE
4824 {
4825  /*
4826  rb_warn("%s is obsolete. use %s instead.",
4827  "WIN32OLE_TYPE.typelibs",
4828  "WIN32OLE_TYPELIB.typelibs.collect{t|t.name}");
4829  */
4830  return rb_eval_string("WIN32OLE_TYPELIB.typelibs.collect{|t|t.name}");
4831 }
4832 
4833 /*
4834  * call-seq:
4835  * WIN32OLE_TYPE.progids
4836  *
4837  * Returns array of ProgID.
4838  */
4839 static VALUE
4841 {
4842  HKEY hclsids, hclsid;
4843  DWORD i;
4844  LONG err;
4845  VALUE clsid;
4846  VALUE v = rb_str_new2("");
4847  VALUE progids = rb_ary_new();
4848 
4849  err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hclsids);
4850  if(err != ERROR_SUCCESS) {
4851  return progids;
4852  }
4853  for(i = 0; ; i++) {
4854  clsid = reg_enum_key(hclsids, i);
4855  if (clsid == Qnil)
4856  break;
4857  err = reg_open_vkey(hclsids, clsid, &hclsid);
4858  if (err != ERROR_SUCCESS)
4859  continue;
4860  if ((v = reg_get_val2(hclsid, "ProgID")) != Qnil)
4861  rb_ary_push(progids, v);
4862  if ((v = reg_get_val2(hclsid, "VersionIndependentProgID")) != Qnil)
4863  rb_ary_push(progids, v);
4864  RegCloseKey(hclsid);
4865  }
4866  RegCloseKey(hclsids);
4867  return progids;
4868 }
4869 
4870 static VALUE
4872 {
4873  struct oletypedata *poletype;
4874  VALUE obj;
4875  ole_initialize();
4876  obj = Data_Make_Struct(klass,struct oletypedata,0,oletype_free,poletype);
4877  poletype->pTypeInfo = NULL;
4878  return obj;
4879 }
4880 
4881 static VALUE
4883 {
4884  struct oletypedata *ptype;
4885  Data_Get_Struct(self, struct oletypedata, ptype);
4886  rb_ivar_set(self, rb_intern("name"), name);
4887  ptype->pTypeInfo = pTypeInfo;
4888  if(pTypeInfo) OLE_ADDREF(pTypeInfo);
4889  return self;
4890 }
4891 
4892 static VALUE
4893 oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass)
4894 {
4895 
4896  long count;
4897  int i;
4898  HRESULT hr;
4899  BSTR bstr;
4900  VALUE typelib;
4901  ITypeInfo *pTypeInfo;
4902 
4903  VALUE found = Qfalse;
4904 
4905  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
4906  for (i = 0; i < count && found == Qfalse; i++) {
4907  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
4908  if (FAILED(hr))
4909  continue;
4910  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
4911  &bstr, NULL, NULL, NULL);
4912  if (FAILED(hr))
4913  continue;
4914  typelib = WC2VSTR(bstr);
4915  if (rb_str_cmp(oleclass, typelib) == 0) {
4916  oletype_set_member(self, pTypeInfo, typelib);
4917  found = Qtrue;
4918  }
4919  OLE_RELEASE(pTypeInfo);
4920  }
4921  return found;
4922 }
4923 
4924 /*
4925  * Document-class: WIN32OLE_TYPELIB
4926  *
4927  * <code>WIN32OLE_TYPELIB</code> objects represent OLE tyblib information.
4928  */
4929 
4930 static VALUE
4931 oletypelib_set_member(VALUE self, ITypeLib *pTypeLib)
4932 {
4933  struct oletypelibdata *ptlib;
4934  Data_Get_Struct(self, struct oletypelibdata, ptlib);
4935  ptlib->pTypeLib = pTypeLib;
4936  return self;
4937 }
4938 
4939 static ITypeLib *
4941 {
4942  struct oletypelibdata *ptlib;
4943  Data_Get_Struct(self, struct oletypelibdata, ptlib);
4944  return ptlib->pTypeLib;
4945 }
4946 
4947 static void
4948 oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr)
4949 {
4950  HRESULT hr;
4951  hr = pTypeLib->lpVtbl->GetLibAttr(pTypeLib, ppTLibAttr);
4952  if (FAILED(hr)) {
4954  "failed to get library attribute(TLIBATTR) from ITypeLib");
4955  }
4956 }
4957 
4958 /*
4959  * call-seq:
4960  *
4961  * WIN32OLE_TYPELIB.typelibs
4962  *
4963  * Returns the array of WIN32OLE_TYPELIB object.
4964  *
4965  * tlibs = WIN32OLE_TYPELIB.typelibs
4966  *
4967  */
4968 static VALUE
4970 {
4971  HKEY htypelib, hguid;
4972  DWORD i, j;
4973  LONG err;
4974  VALUE guid;
4975  VALUE version;
4976  VALUE name = Qnil;
4977  VALUE typelibs = rb_ary_new();
4978  VALUE typelib = Qnil;
4979  HRESULT hr;
4980  ITypeLib *pTypeLib;
4981 
4982  err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
4983  if(err != ERROR_SUCCESS) {
4984  return typelibs;
4985  }
4986  for(i = 0; ; i++) {
4987  guid = reg_enum_key(htypelib, i);
4988  if (guid == Qnil)
4989  break;
4990  err = reg_open_vkey(htypelib, guid, &hguid);
4991  if (err != ERROR_SUCCESS)
4992  continue;
4993  for(j = 0; ; j++) {
4994  version = reg_enum_key(hguid, j);
4995  if (version == Qnil)
4996  break;
4997  if ( (name = reg_get_val2(hguid, StringValuePtr(version))) != Qnil ) {
4998  hr = oletypelib_from_guid(guid, version, &pTypeLib);
4999  if (SUCCEEDED(hr)) {
5000  typelib = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("allocate"), 0);
5001  oletypelib_set_member(typelib, pTypeLib);
5002  rb_ary_push(typelibs, typelib);
5003  }
5004  }
5005  }
5006  RegCloseKey(hguid);
5007  }
5008  RegCloseKey(htypelib);
5009  return typelibs;
5010 }
5011 
5012 static VALUE
5014 {
5015  VALUE version_str = Qnil;
5016  VALUE minor_str = Qnil;
5017  if (major == Qnil) {
5018  return Qnil;
5019  }
5020  version_str = rb_String(major);
5021  if (minor != Qnil) {
5022  minor_str = rb_String(minor);
5023  rb_str_cat2(version_str, ".");
5024  rb_str_append(version_str, minor_str);
5025  }
5026  return version_str;
5027 }
5028 
5029 static VALUE
5031 {
5032  HKEY htypelib, hguid, hversion;
5033  double fver;
5034  DWORD j;
5035  LONG err;
5036  VALUE found = Qfalse;
5037  VALUE tlib;
5038  VALUE ver;
5039  VALUE version_str;
5040  VALUE version = Qnil;
5041  VALUE typelib = Qnil;
5042  HRESULT hr;
5043  ITypeLib *pTypeLib;
5044 
5045  VALUE guid = rb_ary_entry(args, 0);
5046  version_str = make_version_str(rb_ary_entry(args, 1), rb_ary_entry(args, 2));
5047 
5048  err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
5049  if(err != ERROR_SUCCESS) {
5050  return Qfalse;
5051  }
5052  err = reg_open_vkey(htypelib, guid, &hguid);
5053  if (err != ERROR_SUCCESS) {
5054  RegCloseKey(htypelib);
5055  return Qfalse;
5056  }
5057  if (version_str != Qnil) {
5058  err = reg_open_vkey(hguid, version_str, &hversion);
5059  if (err == ERROR_SUCCESS) {
5060  tlib = reg_get_val(hversion, NULL);
5061  if (tlib != Qnil) {
5062  typelib = tlib;
5063  version = version_str;
5064  }
5065  }
5066  RegCloseKey(hversion);
5067  } else {
5068  fver = 0.0;
5069  for(j = 0; ;j++) {
5070  ver = reg_enum_key(hguid, j);
5071  if (ver == Qnil)
5072  break;
5073  err = reg_open_vkey(hguid, ver, &hversion);
5074  if (err != ERROR_SUCCESS)
5075  continue;
5076  tlib = reg_get_val(hversion, NULL);
5077  if (tlib == Qnil) {
5078  RegCloseKey(hversion);
5079  continue;
5080  }
5081  if (fver < atof(StringValuePtr(ver))) {
5082  fver = atof(StringValuePtr(ver));
5083  version = ver;
5084  typelib = tlib;
5085  }
5086  RegCloseKey(hversion);
5087  }
5088  }
5089  RegCloseKey(hguid);
5090  RegCloseKey(htypelib);
5091  if (typelib != Qnil) {
5092  hr = oletypelib_from_guid(guid, version, &pTypeLib);
5093  if (SUCCEEDED(hr)) {
5094  found = Qtrue;
5095  oletypelib_set_member(self, pTypeLib);
5096  }
5097  }
5098  return found;
5099 }
5100 
5101 static VALUE
5103 {
5104  HKEY htypelib, hguid, hversion;
5105  DWORD i, j;
5106  LONG err;
5107  VALUE found = Qfalse;
5108  VALUE tlib;
5109  VALUE guid;
5110  VALUE ver;
5111  HRESULT hr;
5112  ITypeLib *pTypeLib;
5113 
5114  err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
5115  if(err != ERROR_SUCCESS) {
5116  return Qfalse;
5117  }
5118  for(i = 0; !found; i++) {
5119  guid = reg_enum_key(htypelib, i);
5120  if (guid == Qnil)
5121  break;
5122  err = reg_open_vkey(htypelib, guid, &hguid);
5123  if (err != ERROR_SUCCESS)
5124  continue;
5125  for(j = 0; found == Qfalse; j++) {
5126  ver = reg_enum_key(hguid, j);
5127  if (ver == Qnil)
5128  break;
5129  err = reg_open_vkey(hguid, ver, &hversion);
5130  if (err != ERROR_SUCCESS)
5131  continue;
5132  tlib = reg_get_val(hversion, NULL);
5133  if (tlib == Qnil) {
5134  RegCloseKey(hversion);
5135  continue;
5136  }
5137  if (rb_str_cmp(typelib, tlib) == 0) {
5138  hr = oletypelib_from_guid(guid, ver, &pTypeLib);
5139  if (SUCCEEDED(hr)) {
5140  oletypelib_set_member(self, pTypeLib);
5141  found = Qtrue;
5142  }
5143  }
5144  RegCloseKey(hversion);
5145  }
5146  RegCloseKey(hguid);
5147  }
5148  RegCloseKey(htypelib);
5149  return found;
5150 }
5151 
5152 static VALUE
5154 {
5155  struct oletypelibdata *poletypelib;
5156  VALUE obj;
5157  ole_initialize();
5158  obj = Data_Make_Struct(klass, struct oletypelibdata, 0, oletypelib_free, poletypelib);
5159  poletypelib->pTypeLib = NULL;
5160  return obj;
5161 }
5162 
5163 /*
5164  * call-seq:
5165  * WIN32OLE_TYPELIB.new(typelib [, version1, version2]) -> WIN32OLE_TYPELIB object
5166  *
5167  * Returns a new WIN32OLE_TYPELIB object.
5168  *
5169  * The first argument <i>typelib</i> specifies OLE type library name or GUID or
5170  * OLE library file.
5171  * The second argument is major version or version of the type library.
5172  * The third argument is minor version.
5173  * The second argument and third argument are optional.
5174  * If the first argument is type library name, then the second and third argument
5175  * are ignored.
5176  *
5177  * tlib1 = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5178  * tlib2 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}')
5179  * tlib3 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1.3)
5180  * tlib4 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1, 3)
5181  * tlib5 = WIN32OLE_TYPELIB.new("C:\\WINNT\\SYSTEM32\\SHELL32.DLL")
5182  * puts tlib1.name # -> 'Microsoft Excel 9.0 Object Library'
5183  * puts tlib2.name # -> 'Microsoft Excel 9.0 Object Library'
5184  * puts tlib3.name # -> 'Microsoft Excel 9.0 Object Library'
5185  * puts tlib4.name # -> 'Microsoft Excel 9.0 Object Library'
5186  * puts tlib5.name # -> 'Microsoft Shell Controls And Automation'
5187  *
5188  */
5189 static VALUE
5191 {
5192  VALUE found = Qfalse;
5193  VALUE typelib = Qnil;
5194  int len = 0;
5195  OLECHAR * pbuf;
5196  ITypeLib *pTypeLib;
5197  HRESULT hr = S_OK;
5198 
5199  len = RARRAY_LEN(args);
5200  if (len < 1 || len > 3) {
5201  rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", len);
5202  }
5203 
5204  typelib = rb_ary_entry(args, 0);
5205 
5206  SafeStringValue(typelib);
5207 
5208  found = oletypelib_search_registry(self, typelib);
5209  if (found == Qfalse) {
5210  found = oletypelib_search_registry2(self, args);
5211  }
5212  if (found == Qfalse) {
5213  pbuf = ole_vstr2wc(typelib);
5214  hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib);
5215  SysFreeString(pbuf);
5216  if (SUCCEEDED(hr)) {
5217  found = Qtrue;
5218  oletypelib_set_member(self, pTypeLib);
5219  }
5220  }
5221 
5222  if (found == Qfalse) {
5223  rb_raise(eWIN32OLERuntimeError, "not found type library `%s`",
5224  StringValuePtr(typelib));
5225  }
5226  return self;
5227 }
5228 
5229 /*
5230  * call-seq:
5231  * WIN32OLE_TYPELIB#guid -> The guid string.
5232  *
5233  * Returns guid string which specifies type library.
5234  *
5235  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5236  * guid = tlib.guid # -> '{00020813-0000-0000-C000-000000000046}'
5237  */
5238 static VALUE
5240 {
5241  ITypeLib *pTypeLib;
5242  OLECHAR bstr[80];
5243  VALUE guid = Qnil;
5244  int len;
5245  TLIBATTR *pTLibAttr;
5246 
5247  pTypeLib = oletypelib_get_typelib(self);
5248  oletypelib_get_libattr(pTypeLib, &pTLibAttr);
5249  len = StringFromGUID2(&pTLibAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
5250  if (len > 3) {
5251  guid = ole_wc2vstr(bstr, FALSE);
5252  }
5253  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5254  return guid;
5255 }
5256 
5257 /*
5258  * call-seq:
5259  * WIN32OLE_TYPELIB#name -> The type library name
5260  *
5261  * Returns the type library name.
5262  *
5263  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5264  * name = tlib.name # -> 'Microsoft Excel 9.0 Object Library'
5265  */
5266 static VALUE
5268 {
5269  ITypeLib *pTypeLib;
5270  HRESULT hr;
5271  BSTR bstr;
5272  VALUE name;
5273  pTypeLib = oletypelib_get_typelib(self);
5274  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1,
5275  NULL, &bstr, NULL, NULL);
5276 
5277  if (FAILED(hr)) {
5278  ole_raise(hr, eWIN32OLERuntimeError, "failed to get name from ITypeLib");
5279  }
5280  name = WC2VSTR(bstr);
5281  return rb_enc_str_new(StringValuePtr(name), strlen(StringValuePtr(name)), cWIN32OLE_enc);
5282 }
5283 
5284 /*
5285  * call-seq:
5286  * WIN32OLE_TYPELIB#version -> The type library version.
5287  *
5288  * Returns the type library version.
5289  *
5290  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5291  * puts tlib.version #-> 1.3
5292  */
5293 static VALUE
5295 {
5296  TLIBATTR *pTLibAttr;
5297  VALUE major;
5298  VALUE minor;
5299  ITypeLib *pTypeLib;
5300 
5301  pTypeLib = oletypelib_get_typelib(self);
5302  oletypelib_get_libattr(pTypeLib, &pTLibAttr);
5303  major = INT2NUM(pTLibAttr->wMajorVerNum);
5304  minor = INT2NUM(pTLibAttr->wMinorVerNum);
5305  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5306  return rb_Float(make_version_str(major, minor));
5307 }
5308 
5309 /*
5310  * call-seq:
5311  * WIN32OLE_TYPELIB#major_version -> The type library major version.
5312  *
5313  * Returns the type library major version.
5314  *
5315  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5316  * puts tlib.major_version # -> 1
5317  */
5318 static VALUE
5320 {
5321  TLIBATTR *pTLibAttr;
5322  VALUE major;
5323  ITypeLib *pTypeLib;
5324  pTypeLib = oletypelib_get_typelib(self);
5325  oletypelib_get_libattr(pTypeLib, &pTLibAttr);
5326 
5327  major = INT2NUM(pTLibAttr->wMajorVerNum);
5328  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5329  return major;
5330 }
5331 
5332 /*
5333  * call-seq:
5334  * WIN32OLE_TYPELIB#minor_version -> The type library minor version.
5335  *
5336  * Returns the type library minor version.
5337  *
5338  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5339  * puts tlib.minor_version # -> 3
5340  */
5341 static VALUE
5343 {
5344  TLIBATTR *pTLibAttr;
5345  VALUE minor;
5346  ITypeLib *pTypeLib;
5347  pTypeLib = oletypelib_get_typelib(self);
5348  oletypelib_get_libattr(pTypeLib, &pTLibAttr);
5349  minor = INT2NUM(pTLibAttr->wMinorVerNum);
5350  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5351  return minor;
5352 }
5353 
5354 static VALUE
5356 {
5357  int k;
5358  LONG err;
5359  HKEY hkey;
5360  HKEY hlang;
5361  VALUE lang;
5362  VALUE path = Qnil;
5363 
5364  VALUE key = rb_str_new2("TypeLib\\");
5365  rb_str_concat(key, guid);
5366  rb_str_cat2(key, "\\");
5367  rb_str_concat(key, version);
5368 
5369  err = reg_open_vkey(HKEY_CLASSES_ROOT, key, &hkey);
5370  if (err != ERROR_SUCCESS) {
5371  return Qnil;
5372  }
5373  for(k = 0; path == Qnil; k++) {
5374  lang = reg_enum_key(hkey, k);
5375  if (lang == Qnil)
5376  break;
5377  err = reg_open_vkey(hkey, lang, &hlang);
5378  if (err == ERROR_SUCCESS) {
5379  path = reg_get_typelib_file_path(hlang);
5380  RegCloseKey(hlang);
5381  }
5382  }
5383  RegCloseKey(hkey);
5384  return path;
5385 }
5386 
5387 static HRESULT
5388 oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib)
5389 {
5390  VALUE path;
5391  OLECHAR *pBuf;
5392  HRESULT hr;
5393  path = oletypelib_path(guid, version);
5394  if (path == Qnil) {
5395  return E_UNEXPECTED;
5396  }
5397  pBuf = ole_vstr2wc(path);
5398  hr = LoadTypeLibEx(pBuf, REGKIND_NONE, ppTypeLib);
5399  SysFreeString(pBuf);
5400  return hr;
5401 }
5402 
5403 /*
5404  * call-seq:
5405  * WIN32OLE_TYPELIB#path -> The type library file path.
5406  *
5407  * Returns the type library file path.
5408  *
5409  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5410  * puts tlib.path #-> 'C:\...\EXCEL9.OLB'
5411  */
5412 static VALUE
5414 {
5415  TLIBATTR *pTLibAttr;
5416  HRESULT hr = S_OK;
5417  BSTR bstr;
5418  LCID lcid = cWIN32OLE_lcid;
5419  VALUE path;
5420  ITypeLib *pTypeLib;
5421 
5422  pTypeLib = oletypelib_get_typelib(self);
5423  oletypelib_get_libattr(pTypeLib, &pTLibAttr);
5424  hr = QueryPathOfRegTypeLib(&pTLibAttr->guid,
5425  pTLibAttr->wMajorVerNum,
5426  pTLibAttr->wMinorVerNum,
5427  lcid,
5428  &bstr);
5429  if (FAILED(hr)) {
5430  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5431  ole_raise(hr, eWIN32OLERuntimeError, "failed to QueryPathOfRegTypeTypeLib");
5432  }
5433 
5434  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5435  path = WC2VSTR(bstr);
5436  return rb_enc_str_new(StringValuePtr(path), strlen(StringValuePtr(path)), cWIN32OLE_enc);
5437 }
5438 
5439 /*
5440  * call-seq:
5441  * WIN32OLE_TYPELIB#visible?
5442  *
5443  * Returns true if the type library information is not hidden.
5444  * If wLibFlags of TLIBATTR is 0 or LIBFLAG_FRESTRICTED or LIBFLAG_FHIDDEN,
5445  * the method returns false, otherwise, returns true.
5446  * If the method fails to access the TLIBATTR information, then
5447  * WIN32OLERuntimeError is raised.
5448  *
5449  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5450  * tlib.visible? # => true
5451  */
5452 static VALUE
5454 {
5455  ITypeLib *pTypeLib = NULL;
5456  VALUE visible = Qtrue;
5457  TLIBATTR *pTLibAttr;
5458 
5459  pTypeLib = oletypelib_get_typelib(self);
5460  oletypelib_get_libattr(pTypeLib, &pTLibAttr);
5461 
5462  if ((pTLibAttr->wLibFlags == 0) ||
5463  (pTLibAttr->wLibFlags & LIBFLAG_FRESTRICTED) ||
5464  (pTLibAttr->wLibFlags & LIBFLAG_FHIDDEN)) {
5465  visible = Qfalse;
5466  }
5467  pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
5468  return visible;
5469 }
5470 
5471 /*
5472  * call-seq:
5473  * WIN32OLE_TYPELIB#library_name
5474  *
5475  * Returns library name.
5476  * If the method fails to access library name, WIN32OLERuntimeError is raised.
5477  *
5478  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5479  * tlib.library_name # => Excel
5480  */
5481 static VALUE
5483 {
5484  HRESULT hr;
5485  ITypeLib *pTypeLib = NULL;
5486  VALUE libname = Qnil;
5487  BSTR bstr;
5488 
5489  pTypeLib = oletypelib_get_typelib(self);
5490  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1,
5491  &bstr, NULL, NULL, NULL);
5492  if (FAILED(hr)) {
5493  ole_raise(hr, eWIN32OLERuntimeError, "failed to get library name");
5494  }
5495  libname = WC2VSTR(bstr);
5496  return libname;
5497 }
5498 
5499 
5500 /*
5501  * call-seq:
5502  * WIN32OLE_TYPELIB#ole_types -> The array of WIN32OLE_TYPE object included the type library.
5503  *
5504  * Returns the type library file path.
5505  *
5506  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5507  * classes = tlib.ole_types.collect{|k| k.name} # -> ['AddIn', 'AddIns' ...]
5508  */
5509 static VALUE
5511 {
5512  ITypeLib *pTypeLib = NULL;
5513  VALUE classes = rb_ary_new();
5514  pTypeLib = oletypelib_get_typelib(self);
5515  ole_types_from_typelib(pTypeLib, classes);
5516  return classes;
5517 }
5518 
5519 /*
5520  * call-seq:
5521  * WIN32OLE_TYPELIB#inspect -> String
5522  *
5523  * Returns the type library name with class name.
5524  *
5525  * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
5526  * tlib.inspect # => "<#WIN32OLE_TYPELIB:Microsoft Excel 9.0 Object Library>"
5527  */
5528 static VALUE
5530 {
5531  return default_inspect(self, "WIN32OLE_TYPELIB");
5532 }
5533 
5534 /*
5535  * Document-class: WIN32OLE_TYPE
5536  *
5537  * <code>WIN32OLE_TYPE</code> objects represent OLE type libarary information.
5538  */
5539 
5540 /*
5541  * call-seq:
5542  * WIN32OLE_TYPE.new(typelib, ole_class) -> WIN32OLE_TYPE object
5543  *
5544  * Returns a new WIN32OLE_TYPE object.
5545  * The first argument <i>typelib</i> specifies OLE type library name.
5546  * The second argument specifies OLE class name.
5547  *
5548  * WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
5549  * # => WIN32OLE_TYPE object of Application class of Excel.
5550  */
5551 static VALUE
5552 foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass)
5553 {
5554  VALUE file;
5555  OLECHAR * pbuf;
5556  ITypeLib *pTypeLib;
5557  HRESULT hr;
5558 
5559  SafeStringValue(oleclass);
5560  SafeStringValue(typelib);
5561  file = typelib_file(typelib);
5562  if (file == Qnil) {
5563  file = typelib;
5564  }
5565  pbuf = ole_vstr2wc(file);
5566  hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib);
5567  if (FAILED(hr))
5568  ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx");
5569  SysFreeString(pbuf);
5570  if (oleclass_from_typelib(self, pTypeLib, oleclass) == Qfalse) {
5571  OLE_RELEASE(pTypeLib);
5572  rb_raise(eWIN32OLERuntimeError, "not found `%s` in `%s`",
5573  StringValuePtr(oleclass), StringValuePtr(typelib));
5574  }
5575  OLE_RELEASE(pTypeLib);
5576  return self;
5577 }
5578 
5579 /*
5580  * call-seq:
5581  * WIN32OLE_TYPE#name #=> OLE type name
5582  *
5583  * Returns OLE type name.
5584  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
5585  * puts tobj.name # => Application
5586  */
5587 static VALUE
5589 {
5590  return rb_ivar_get(self, rb_intern("name"));
5591 }
5592 
5593 static VALUE
5594 ole_ole_type(ITypeInfo *pTypeInfo)
5595 {
5596  HRESULT hr;
5597  TYPEATTR *pTypeAttr;
5598  VALUE type = Qnil;
5599  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5600  if(FAILED(hr)){
5601  return type;
5602  }
5603  switch(pTypeAttr->typekind) {
5604  case TKIND_ENUM:
5605  type = rb_str_new2("Enum");
5606  break;
5607  case TKIND_RECORD:
5608  type = rb_str_new2("Record");
5609  break;
5610  case TKIND_MODULE:
5611  type = rb_str_new2("Module");
5612  break;
5613  case TKIND_INTERFACE:
5614  type = rb_str_new2("Interface");
5615  break;
5616  case TKIND_DISPATCH:
5617  type = rb_str_new2("Dispatch");
5618  break;
5619  case TKIND_COCLASS:
5620  type = rb_str_new2("Class");
5621  break;
5622  case TKIND_ALIAS:
5623  type = rb_str_new2("Alias");
5624  break;
5625  case TKIND_UNION:
5626  type = rb_str_new2("Union");
5627  break;
5628  case TKIND_MAX:
5629  type = rb_str_new2("Max");
5630  break;
5631  default:
5632  type = Qnil;
5633  break;
5634  }
5635  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5636  return type;
5637 }
5638 
5639 /*
5640  * call-seq:
5641  * WIN32OLE_TYPE#ole_type #=> OLE type string.
5642  *
5643  * returns type of OLE class.
5644  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
5645  * puts tobj.ole_type # => Class
5646  */
5647 static VALUE
5649 {
5650  struct oletypedata *ptype;
5651  Data_Get_Struct(self, struct oletypedata, ptype);
5652  return ole_ole_type(ptype->pTypeInfo);
5653 }
5654 
5655 static VALUE
5657 {
5658  HRESULT hr;
5659  TYPEATTR *pTypeAttr;
5660  int len;
5661  OLECHAR bstr[80];
5662  VALUE guid = Qnil;
5663  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5664  if (FAILED(hr))
5665  return guid;
5666  len = StringFromGUID2(&pTypeAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
5667  if (len > 3) {
5668  guid = ole_wc2vstr(bstr, FALSE);
5669  }
5670  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5671  return guid;
5672 }
5673 
5674 /*
5675  * call-seq:
5676  * WIN32OLE_TYPE#guid #=> GUID
5677  *
5678  * Returns GUID.
5679  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
5680  * puts tobj.guid # => {00024500-0000-0000-C000-000000000046}
5681  */
5682 static VALUE
5684 {
5685  struct oletypedata *ptype;
5686  Data_Get_Struct(self, struct oletypedata, ptype);
5687  return ole_type_guid(ptype->pTypeInfo);
5688 }
5689 
5690 static VALUE
5692 {
5693  HRESULT hr;
5694  TYPEATTR *pTypeAttr;
5695  OLECHAR *pbuf;
5696  VALUE progid = Qnil;
5697  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5698  if (FAILED(hr))
5699  return progid;
5700  hr = ProgIDFromCLSID(&pTypeAttr->guid, &pbuf);
5701  if (SUCCEEDED(hr)) {
5702  progid = ole_wc2vstr(pbuf, FALSE);
5703  CoTaskMemFree(pbuf);
5704  }
5705  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5706  return progid;
5707 }
5708 
5709 /*
5710  * call-seq:
5711  * WIN32OLE_TYPE#progid #=> ProgID
5712  *
5713  * Returns ProgID if it exists. If not found, then returns nil.
5714  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
5715  * puts tobj.progid # => Excel.Application.9
5716  */
5717 static VALUE
5719 {
5720  struct oletypedata *ptype;
5721  Data_Get_Struct(self, struct oletypedata, ptype);
5722  return ole_type_progid(ptype->pTypeInfo);
5723 }
5724 
5725 
5726 static VALUE
5728 {
5729  HRESULT hr;
5730  TYPEATTR *pTypeAttr;
5731  VALUE visible;
5732  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5733  if (FAILED(hr))
5734  return Qtrue;
5735  if (pTypeAttr->wTypeFlags & (TYPEFLAG_FHIDDEN | TYPEFLAG_FRESTRICTED)) {
5736  visible = Qfalse;
5737  } else {
5738  visible = Qtrue;
5739  }
5740  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5741  return visible;
5742 }
5743 
5744 /*
5745  * call-seq:
5746  * WIN32OLE_TYPE#visible #=> true or false
5747  *
5748  * Returns true if the OLE class is public.
5749  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
5750  * puts tobj.visible # => true
5751  */
5752 static VALUE
5754 {
5755  struct oletypedata *ptype;
5756  Data_Get_Struct(self, struct oletypedata, ptype);
5757  return ole_type_visible(ptype->pTypeInfo);
5758 }
5759 
5760 static VALUE
5762 {
5763  VALUE ver;
5764  TYPEATTR *pTypeAttr;
5765  HRESULT hr;
5766  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5767  if (FAILED(hr))
5768  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
5769  ver = INT2FIX(pTypeAttr->wMajorVerNum);
5770  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5771  return ver;
5772 }
5773 
5774 /*
5775  * call-seq:
5776  * WIN32OLE_TYPE#major_version
5777  *
5778  * Returns major version.
5779  * tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
5780  * puts tobj.major_version # => 8
5781  */
5782 static VALUE
5784 {
5785  struct oletypedata *ptype;
5786  Data_Get_Struct(self, struct oletypedata, ptype);
5787  return ole_type_major_version(ptype->pTypeInfo);
5788 }
5789 
5790 static VALUE
5792 {
5793  VALUE ver;
5794  TYPEATTR *pTypeAttr;
5795  HRESULT hr;
5796  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5797  if (FAILED(hr))
5798  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
5799  ver = INT2FIX(pTypeAttr->wMinorVerNum);
5800  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5801  return ver;
5802 }
5803 
5804 /*
5805  * call-seq:
5806  * WIN32OLE_TYPE#minor_version #=> OLE minor version
5807  *
5808  * Returns minor version.
5809  * tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
5810  * puts tobj.minor_version # => 2
5811  */
5812 static VALUE
5814 {
5815  struct oletypedata *ptype;
5816  Data_Get_Struct(self, struct oletypedata, ptype);
5817  return ole_type_minor_version(ptype->pTypeInfo);
5818 }
5819 
5820 static VALUE
5822 {
5823  VALUE typekind;
5824  TYPEATTR *pTypeAttr;
5825  HRESULT hr;
5826  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5827  if (FAILED(hr))
5828  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
5829  typekind = INT2FIX(pTypeAttr->typekind);
5830  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5831  return typekind;
5832 }
5833 
5834 /*
5835  * call-seq:
5836  * WIN32OLE_TYPE#typekind #=> number of type.
5837  *
5838  * Returns number which represents type.
5839  * tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
5840  * puts tobj.typekind # => 4
5841  *
5842  */
5843 static VALUE
5845 {
5846  struct oletypedata *ptype;
5847  Data_Get_Struct(self, struct oletypedata, ptype);
5848  return ole_type_typekind(ptype->pTypeInfo);
5849 }
5850 
5851 static VALUE
5853 {
5854  HRESULT hr;
5855  BSTR bhelpstr;
5856  hr = ole_docinfo_from_type(pTypeInfo, NULL, &bhelpstr, NULL, NULL);
5857  if(FAILED(hr)) {
5858  return Qnil;
5859  }
5860  return WC2VSTR(bhelpstr);
5861 }
5862 
5863 /*
5864  * call-seq:
5865  * WIN32OLE_TYPE#helpstring #=> help string.
5866  *
5867  * Returns help string.
5868  * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'IWebBrowser')
5869  * puts tobj.helpstring # => Web Browser interface
5870  */
5871 static VALUE
5873 {
5874  struct oletypedata *ptype;
5875  Data_Get_Struct(self, struct oletypedata, ptype);
5876  return ole_type_helpstring(ptype->pTypeInfo);
5877 }
5878 
5879 static VALUE
5881 {
5882  HRESULT hr;
5883  TYPEATTR *pTypeAttr;
5884  VALUE alias = Qnil;
5885  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
5886  if (FAILED(hr))
5887  return alias;
5888  if(pTypeAttr->typekind != TKIND_ALIAS) {
5889  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5890  return alias;
5891  }
5892  alias = ole_typedesc2val(pTypeInfo, &(pTypeAttr->tdescAlias), Qnil);
5893  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5894  return alias;
5895 }
5896 
5897 /*
5898  * call-seq:
5899  * WIN32OLE_TYPE#src_type #=> OLE source class
5900  *
5901  * Returns source class when the OLE class is 'Alias'.
5902  * tobj = WIN32OLE_TYPE.new('Microsoft Office 9.0 Object Library', 'MsoRGBType')
5903  * puts tobj.src_type # => I4
5904  *
5905  */
5906 static VALUE
5908 {
5909  struct oletypedata *ptype;
5910  Data_Get_Struct(self, struct oletypedata, ptype);
5911  return ole_type_src_type(ptype->pTypeInfo);
5912 }
5913 
5914 static VALUE
5916 {
5917  HRESULT hr;
5918  BSTR bhelpfile;
5919  hr = ole_docinfo_from_type(pTypeInfo, NULL, NULL, NULL, &bhelpfile);
5920  if(FAILED(hr)) {
5921  return Qnil;
5922  }
5923  return WC2VSTR(bhelpfile);
5924 }
5925 
5926 /*
5927  * call-seq:
5928  * WIN32OLE_TYPE#helpfile
5929  *
5930  * Returns helpfile path. If helpfile is not found, then returns nil.
5931  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
5932  * puts tobj.helpfile # => C:\...\VBAXL9.CHM
5933  *
5934  */
5935 static VALUE
5937 {
5938  struct oletypedata *ptype;
5939  Data_Get_Struct(self, struct oletypedata, ptype);
5940  return ole_type_helpfile(ptype->pTypeInfo);
5941 }
5942 
5943 static VALUE
5945 {
5946  HRESULT hr;
5947  DWORD helpcontext;
5948  hr = ole_docinfo_from_type(pTypeInfo, NULL, NULL,
5949  &helpcontext, NULL);
5950  if(FAILED(hr))
5951  return Qnil;
5952  return INT2FIX(helpcontext);
5953 }
5954 
5955 /*
5956  * call-seq:
5957  * WIN32OLE_TYPE#helpcontext
5958  *
5959  * Returns helpcontext. If helpcontext is not found, then returns nil.
5960  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
5961  * puts tobj.helpfile # => 131185
5962  */
5963 static VALUE
5965 {
5966  struct oletypedata *ptype;
5967  Data_Get_Struct(self, struct oletypedata, ptype);
5968  return ole_type_helpcontext(ptype->pTypeInfo);
5969 }
5970 
5971 /*
5972  * call-seq:
5973  * WIN32OLE_TYPE#ole_typelib
5974  *
5975  * Returns the WIN32OLE_TYPELIB object which is including the WIN32OLE_TYPE
5976  * object. If it is not found, then returns nil.
5977  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
5978  * puts tobj.ole_typelib # => 'Microsoft Excel 9.0 Object Library'
5979  */
5980 static VALUE
5982 {
5983  struct oletypedata *ptype;
5984  Data_Get_Struct(self, struct oletypedata, ptype);
5985  return ole_typelib_from_itypeinfo(ptype->pTypeInfo);
5986 }
5987 
5988 static VALUE
5989 ole_type_impl_ole_types(ITypeInfo *pTypeInfo, int implflags)
5990 {
5991  HRESULT hr;
5992  ITypeInfo *pRefTypeInfo;
5993  HREFTYPE href;
5994  WORD i;
5995  VALUE type;
5996  TYPEATTR *pTypeAttr;
5997  int flags;
5998 
5999  VALUE types = rb_ary_new();
6000  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
6001  if (FAILED(hr)) {
6002  return types;
6003  }
6004  for (i = 0; i < pTypeAttr->cImplTypes; i++) {
6005  hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
6006  if (FAILED(hr))
6007  continue;
6008 
6009  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
6010  if (FAILED(hr))
6011  continue;
6012  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
6013  if (FAILED(hr))
6014  continue;
6015 
6016  if ((flags & implflags) == implflags) {
6017  type = ole_type_from_itypeinfo(pRefTypeInfo);
6018  if (type != Qnil) {
6019  rb_ary_push(types, type);
6020  }
6021  }
6022 
6023  OLE_RELEASE(pRefTypeInfo);
6024  }
6025  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
6026  return types;
6027 }
6028 
6029 /*
6030  * call-seq:
6031  * WIN32OLE_TYPE#implemented_ole_types
6032  *
6033  * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
6034  * object.
6035  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
6036  * p tobj.implemented_ole_types # => [_Worksheet, DocEvents]
6037  */
6038 static VALUE
6040 {
6041  struct oletypedata *ptype;
6042  Data_Get_Struct(self, struct oletypedata, ptype);
6043  return ole_type_impl_ole_types(ptype->pTypeInfo, 0);
6044 }
6045 
6046 /*
6047  * call-seq:
6048  * WIN32OLE_TYPE#source_ole_types
6049  *
6050  * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
6051  * object and having IMPLTYPEFLAG_FSOURCE.
6052  * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
6053  * p tobj.source_ole_types
6054  * # => [#<WIN32OLE_TYPE:DWebBrowserEvents2>, #<WIN32OLE_TYPE:DWebBrowserEvents>]
6055  */
6056 static VALUE
6058 {
6059  struct oletypedata *ptype;
6060  Data_Get_Struct(self, struct oletypedata, ptype);
6061  return ole_type_impl_ole_types(ptype->pTypeInfo, IMPLTYPEFLAG_FSOURCE);
6062 }
6063 
6064 /*
6065  * call-seq:
6066  * WIN32OLE_TYPE#default_event_sources
6067  *
6068  * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
6069  * object and having IMPLTYPEFLAG_FSOURCE and IMPLTYPEFLAG_FDEFAULT.
6070  * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
6071  * p tobj.default_event_sources # => [#<WIN32OLE_TYPE:DWebBrowserEvents2>]
6072  */
6073 static VALUE
6075 {
6076  struct oletypedata *ptype;
6077  Data_Get_Struct(self, struct oletypedata, ptype);
6078  return ole_type_impl_ole_types(ptype->pTypeInfo, IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT);
6079 }
6080 
6081 /*
6082  * call-seq:
6083  * WIN32OLE_TYPE#default_ole_types
6084  *
6085  * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
6086  * object and having IMPLTYPEFLAG_FDEFAULT.
6087  * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
6088  * p tobj.default_ole_types
6089  * # => [#<WIN32OLE_TYPE:IWebBrowser2>, #<WIN32OLE_TYPE:DWebBrowserEvents2>]
6090  */
6091 static VALUE
6093 {
6094  struct oletypedata *ptype;
6095  Data_Get_Struct(self, struct oletypedata, ptype);
6096  return ole_type_impl_ole_types(ptype->pTypeInfo, IMPLTYPEFLAG_FDEFAULT);
6097 }
6098 
6099 /*
6100  * call-seq:
6101  * WIN32OLE_TYPE#inspect -> String
6102  *
6103  * Returns the type name with class name.
6104  *
6105  * ie = WIN32OLE.new('InternetExplorer.Application')
6106  * ie.ole_type.inspect => #<WIN32OLE_TYPE:IWebBrowser2>
6107  */
6108 static VALUE
6110 {
6111  return default_inspect(self, "WIN32OLE_TYPE");
6112 }
6113 
6114 static VALUE
6116 {
6117  HRESULT hr;
6118  TYPEATTR *pTypeAttr;
6119  WORD i;
6120  UINT len;
6121  BSTR bstr;
6122  char *pstr;
6123  VARDESC *pVarDesc;
6124  struct olevariabledata *pvar;
6125  VALUE var;
6126  VALUE variables = rb_ary_new();
6127  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
6128  if (FAILED(hr)) {
6129  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
6130  }
6131 
6132  for(i = 0; i < pTypeAttr->cVars; i++) {
6133  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, i, &pVarDesc);
6134  if(FAILED(hr))
6135  continue;
6136  len = 0;
6137  pstr = NULL;
6138  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
6139  1, &len);
6140  if(FAILED(hr) || len == 0 || !bstr)
6141  continue;
6142 
6144  0,olevariable_free,pvar);
6145  pvar->pTypeInfo = pTypeInfo;
6146  OLE_ADDREF(pTypeInfo);
6147  pvar->index = i;
6148  rb_ivar_set(var, rb_intern("name"), WC2VSTR(bstr));
6149  rb_ary_push(variables, var);
6150 
6151  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6152  pVarDesc = NULL;
6153  }
6154  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
6155  return variables;
6156 }
6157 
6158 /*
6159  * call-seq:
6160  * WIN32OLE_TYPE#variables
6161  *
6162  * Returns array of WIN32OLE_VARIABLE objects which represent variables
6163  * defined in OLE class.
6164  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6165  * vars = tobj.variables
6166  * vars.each do |v|
6167  * puts "#{v.name} = #{v.value}"
6168  * end
6169  *
6170  * The result of above sample script is follows:
6171  * xlChart = -4109
6172  * xlDialogSheet = -4116
6173  * xlExcel4IntlMacroSheet = 4
6174  * xlExcel4MacroSheet = 3
6175  * xlWorksheet = -4167
6176  *
6177  */
6178 static VALUE
6180 {
6181  struct oletypedata *ptype;
6182  Data_Get_Struct(self, struct oletypedata, ptype);
6183  return ole_variables(ptype->pTypeInfo);
6184 }
6185 
6186 /*
6187  * call-seq:
6188  * WIN32OLE_TYPE#ole_methods # the array of WIN32OLE_METHOD objects.
6189  *
6190  * Returns array of WIN32OLE_METHOD objects which represent OLE method defined in
6191  * OLE type library.
6192  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
6193  * methods = tobj.ole_methods.collect{|m|
6194  * m.name
6195  * }
6196  * # => ['Activate', 'Copy', 'Delete',....]
6197  */
6198 static VALUE
6200 {
6201  struct oletypedata *ptype;
6202  Data_Get_Struct(self, struct oletypedata, ptype);
6203  return ole_methods_from_typeinfo(ptype->pTypeInfo, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
6204 }
6205 
6206 /*
6207  * Document-class: WIN32OLE_VARIABLE
6208  *
6209  * <code>WIN32OLE_VARIABLE</code> objects represent OLE variable information.
6210  */
6211 
6212 /*
6213  * call-seq:
6214  * WIN32OLE_VARIABLE#name
6215  *
6216  * Returns the name of variable.
6217  *
6218  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6219  * variables = tobj.variables
6220  * variables.each do |variable|
6221  * puts "#{variable.name}"
6222  * end
6223  *
6224  * The result of above script is following:
6225  * xlChart
6226  * xlDialogSheet
6227  * xlExcel4IntlMacroSheet
6228  * xlExcel4MacroSheet
6229  * xlWorksheet
6230  *
6231  */
6232 static VALUE
6234 {
6235  return rb_ivar_get(self, rb_intern("name"));
6236 }
6237 
6238 static VALUE
6239 ole_variable_ole_type(ITypeInfo *pTypeInfo, UINT var_index)
6240 {
6241  VARDESC *pVarDesc;
6242  HRESULT hr;
6243  VALUE type;
6244  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
6245  if (FAILED(hr))
6246  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetVarDesc");
6247  type = ole_typedesc2val(pTypeInfo, &(pVarDesc->elemdescVar.tdesc), Qnil);
6248  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6249  return type;
6250 }
6251 
6252 /*
6253  * call-seq:
6254  * WIN32OLE_VARIABLE#ole_type
6255  *
6256  * Returns OLE type string.
6257  *
6258  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6259  * variables = tobj.variables
6260  * variables.each do |variable|
6261  * puts "#{variable.ole_type} #{variable.name}"
6262  * end
6263  *
6264  * The result of above script is following:
6265  * INT xlChart
6266  * INT xlDialogSheet
6267  * INT xlExcel4IntlMacroSheet
6268  * INT xlExcel4MacroSheet
6269  * INT xlWorksheet
6270  *
6271  */
6272 static VALUE
6274 {
6275  struct olevariabledata *pvar;
6276  Data_Get_Struct(self, struct olevariabledata, pvar);
6277  return ole_variable_ole_type(pvar->pTypeInfo, pvar->index);
6278 }
6279 
6280 static VALUE
6281 ole_variable_ole_type_detail(ITypeInfo *pTypeInfo, UINT var_index)
6282 {
6283  VARDESC *pVarDesc;
6284  HRESULT hr;
6285  VALUE type = rb_ary_new();
6286  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
6287  if (FAILED(hr))
6288  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetVarDesc");
6289  ole_typedesc2val(pTypeInfo, &(pVarDesc->elemdescVar.tdesc), type);
6290  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6291  return type;
6292 }
6293 
6294 /*
6295  * call-seq:
6296  * WIN32OLE_VARIABLE#ole_type_detail
6297  *
6298  * Returns detail information of type. The information is array of type.
6299  *
6300  * tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library', 'D3DCLIPSTATUS')
6301  * variable = tobj.variables.find {|variable| variable.name == 'lFlags'}
6302  * tdetail = variable.ole_type_detail
6303  * p tdetail # => ["USERDEFINED", "CONST_D3DCLIPSTATUSFLAGS"]
6304  *
6305  */
6306 static VALUE
6308 {
6309  struct olevariabledata *pvar;
6310  Data_Get_Struct(self, struct olevariabledata, pvar);
6311  return ole_variable_ole_type_detail(pvar->pTypeInfo, pvar->index);
6312 }
6313 
6314 static VALUE
6315 ole_variable_value(ITypeInfo *pTypeInfo, UINT var_index)
6316 {
6317  VARDESC *pVarDesc;
6318  HRESULT hr;
6319  VALUE val = Qnil;
6320  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
6321  if (FAILED(hr))
6322  return Qnil;
6323  if(pVarDesc->varkind == VAR_CONST)
6324  val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
6325  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6326  return val;
6327 }
6328 
6329 /*
6330  * call-seq:
6331  * WIN32OLE_VARIABLE#value
6332  *
6333  * Returns value if value is exists. If the value does not exist,
6334  * this method returns nil.
6335  *
6336  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6337  * variables = tobj.variables
6338  * variables.each do |variable|
6339  * puts "#{variable.name} #{variable.value}"
6340  * end
6341  *
6342  * The result of above script is following:
6343  * xlChart = -4109
6344  * xlDialogSheet = -4116
6345  * xlExcel4IntlMacroSheet = 4
6346  * xlExcel4MacroSheet = 3
6347  * xlWorksheet = -4167
6348  *
6349  */
6350 static VALUE
6352 {
6353  struct olevariabledata *pvar;
6354  Data_Get_Struct(self, struct olevariabledata, pvar);
6355  return ole_variable_value(pvar->pTypeInfo, pvar->index);
6356 }
6357 
6358 static VALUE
6359 ole_variable_visible(ITypeInfo *pTypeInfo, UINT var_index)
6360 {
6361  VARDESC *pVarDesc;
6362  HRESULT hr;
6363  VALUE visible = Qfalse;
6364  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
6365  if (FAILED(hr))
6366  return visible;
6367  if (!(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
6368  VARFLAG_FRESTRICTED |
6369  VARFLAG_FNONBROWSABLE))) {
6370  visible = Qtrue;
6371  }
6372  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6373  return visible;
6374 }
6375 
6376 /*
6377  * call-seq:
6378  * WIN32OLE_VARIABLE#visible?
6379  *
6380  * Returns true if the variable is public.
6381  *
6382  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6383  * variables = tobj.variables
6384  * variables.each do |variable|
6385  * puts "#{variable.name} #{variable.visible?}"
6386  * end
6387  *
6388  * The result of above script is following:
6389  * xlChart true
6390  * xlDialogSheet true
6391  * xlExcel4IntlMacroSheet true
6392  * xlExcel4MacroSheet true
6393  * xlWorksheet true
6394  *
6395  */
6396 static VALUE
6398 {
6399  struct olevariabledata *pvar;
6400  Data_Get_Struct(self, struct olevariabledata, pvar);
6401  return ole_variable_visible(pvar->pTypeInfo, pvar->index);
6402 }
6403 
6404 static VALUE
6405 ole_variable_kind(ITypeInfo *pTypeInfo, UINT var_index)
6406 {
6407  VARDESC *pVarDesc;
6408  HRESULT hr;
6409  VALUE kind = rb_str_new2("UNKNOWN");
6410  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
6411  if (FAILED(hr))
6412  return kind;
6413  switch(pVarDesc->varkind) {
6414  case VAR_PERINSTANCE:
6415  kind = rb_str_new2("PERINSTANCE");
6416  break;
6417  case VAR_STATIC:
6418  kind = rb_str_new2("STATIC");
6419  break;
6420  case VAR_CONST:
6421  kind = rb_str_new2("CONSTANT");
6422  break;
6423  case VAR_DISPATCH:
6424  kind = rb_str_new2("DISPATCH");
6425  break;
6426  default:
6427  break;
6428  }
6429  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6430  return kind;
6431 }
6432 
6433 /*
6434  * call-seq:
6435  * WIN32OLE_VARIABLE#variable_kind
6436  *
6437  * Returns variable kind string.
6438  *
6439  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6440  * variables = tobj.variables
6441  * variables.each do |variable|
6442  * puts "#{variable.name} #{variable.variable_kind}"
6443  * end
6444  *
6445  * The result of above script is following:
6446  * xlChart CONSTANT
6447  * xlDialogSheet CONSTANT
6448  * xlExcel4IntlMacroSheet CONSTANT
6449  * xlExcel4MacroSheet CONSTANT
6450  * xlWorksheet CONSTANT
6451  */
6452 static VALUE
6454 {
6455  struct olevariabledata *pvar;
6456  Data_Get_Struct(self, struct olevariabledata, pvar);
6457  return ole_variable_kind(pvar->pTypeInfo, pvar->index);
6458 }
6459 
6460 static VALUE
6461 ole_variable_varkind(ITypeInfo *pTypeInfo, UINT var_index)
6462 {
6463  VARDESC *pVarDesc;
6464  HRESULT hr;
6465  VALUE kind = Qnil;
6466  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
6467  if (FAILED(hr))
6468  return kind;
6469  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
6470  kind = INT2FIX(pVarDesc->varkind);
6471  return kind;
6472 }
6473 
6474 /*
6475  * call-seq:
6476  * WIN32OLE_VARIABLE#varkind
6477  *
6478  * Returns the number which represents variable kind.
6479  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
6480  * variables = tobj.variables
6481  * variables.each do |variable|
6482  * puts "#{variable.name} #{variable.varkind}"
6483  * end
6484  *
6485  * The result of above script is following:
6486  * xlChart 2
6487  * xlDialogSheet 2
6488  * xlExcel4IntlMacroSheet 2
6489  * xlExcel4MacroSheet 2
6490  * xlWorksheet 2
6491  */
6492 static VALUE
6494 {
6495  struct olevariabledata *pvar;
6496  Data_Get_Struct(self, struct olevariabledata, pvar);
6497  return ole_variable_varkind(pvar->pTypeInfo, pvar->index);
6498 }
6499 
6500 /*
6501  * call-seq:
6502  * WIN32OLE_VARIABLE#inspect -> String
6503  *
6504  * Returns the OLE variable name and the value with class name.
6505  *
6506  */
6507 static VALUE
6509 {
6510  VALUE detail = rb_funcall(self, rb_intern("to_s"), 0);
6511  rb_str_cat2(detail, "=");
6512  rb_str_concat(detail, rb_funcall(rb_funcall(self, rb_intern("value"), 0), rb_intern("inspect"), 0));
6513  return make_inspect("WIN32OLE_VARIABLE", detail);
6514 }
6515 
6516 /*
6517  * Document-class: WIN32OLE_METHOD
6518  *
6519  * <code>WIN32OLE_METHOD</code> objects represent OLE method information.
6520  */
6521 
6522 static VALUE
6523 olemethod_set_member(VALUE self, ITypeInfo *pTypeInfo, ITypeInfo *pOwnerTypeInfo, int index, VALUE name)
6524 {
6525  struct olemethoddata *pmethod;
6526  Data_Get_Struct(self, struct olemethoddata, pmethod);
6527  pmethod->pTypeInfo = pTypeInfo;
6528  OLE_ADDREF(pTypeInfo);
6529  pmethod->pOwnerTypeInfo = pOwnerTypeInfo;
6530  if(pOwnerTypeInfo) OLE_ADDREF(pOwnerTypeInfo);
6531  pmethod->index = index;
6532  rb_ivar_set(self, rb_intern("name"), name);
6533  return self;
6534 }
6535 
6536 static VALUE
6538 {
6539  struct olemethoddata *pmethod;
6540  VALUE obj;
6541  obj = Data_Make_Struct(klass,
6542  struct olemethoddata,
6543  0, olemethod_free, pmethod);
6544  pmethod->pTypeInfo = NULL;
6545  pmethod->pOwnerTypeInfo = NULL;
6546  pmethod->index = 0;
6547  return obj;
6548 }
6549 
6550 /*
6551  * call-seq:
6552  * WIN32OLE_METHOD.new(ole_type, method) -> WIN32OLE_METHOD object
6553  *
6554  * Returns a new WIN32OLE_METHOD object which represents the information
6555  * about OLE method.
6556  * The first argument <i>ole_type</i> specifies WIN32OLE_TYPE object.
6557  * The second argument <i>method</i> specifies OLE method name defined OLE class
6558  * which represents WIN32OLE_TYPE object.
6559  *
6560  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
6561  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
6562  */
6563 static VALUE
6564 folemethod_initialize(VALUE self, VALUE oletype, VALUE method)
6565 {
6566  struct oletypedata *ptype;
6567  VALUE obj = Qnil;
6568  if (rb_obj_is_kind_of(oletype, cWIN32OLE_TYPE)) {
6569  SafeStringValue(method);
6570  Data_Get_Struct(oletype, struct oletypedata, ptype);
6571  obj = olemethod_from_typeinfo(self, ptype->pTypeInfo, method);
6572  if (obj == Qnil) {
6573  rb_raise(eWIN32OLERuntimeError, "not found %s",
6574  StringValuePtr(method));
6575  }
6576  }
6577  else {
6578  rb_raise(rb_eTypeError, "1st argument should be WIN32OLE_TYPE object");
6579  }
6580  return obj;
6581 }
6582 
6583 /*
6584  * call-seq
6585  * WIN32OLE_METHOD#name
6586  *
6587  * Returns the name of the method.
6588  *
6589  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
6590  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
6591  * puts method.name # => SaveAs
6592  *
6593  */
6594 static VALUE
6596 {
6597  return rb_ivar_get(self, rb_intern("name"));
6598 }
6599 
6600 static VALUE
6601 ole_method_return_type(ITypeInfo *pTypeInfo, UINT method_index)
6602 {
6603  FUNCDESC *pFuncDesc;
6604  HRESULT hr;
6605  VALUE type;
6606 
6607  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
6608  if (FAILED(hr))
6609  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetFuncDesc");
6610 
6611  type = ole_typedesc2val(pTypeInfo, &(pFuncDesc->elemdescFunc.tdesc), Qnil);
6612  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
6613  return type;
6614 }
6615 
6616 /*
6617  * call-seq:
6618  * WIN32OLE_METHOD#return_type
6619  *
6620  * Returns string of return value type of method.
6621  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6622  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6623  * puts method.return_type # => Workbook
6624  *
6625  */
6626 static VALUE
6628 {
6629  struct olemethoddata *pmethod;
6630  Data_Get_Struct(self, struct olemethoddata, pmethod);
6631  return ole_method_return_type(pmethod->pTypeInfo, pmethod->index);
6632 }
6633 
6634 static VALUE
6635 ole_method_return_vtype(ITypeInfo *pTypeInfo, UINT method_index)
6636 {
6637  FUNCDESC *pFuncDesc;
6638  HRESULT hr;
6639  VALUE vvt;
6640 
6641  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
6642  if (FAILED(hr))
6643  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetFuncDesc");
6644 
6645  vvt = INT2FIX(pFuncDesc->elemdescFunc.tdesc.vt);
6646  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
6647  return vvt;
6648 }
6649 
6650 /*
6651  * call-seq:
6652  * WIN32OLE_METHOD#return_vtype
6653  *
6654  * Returns number of return value type of method.
6655  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6656  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6657  * puts method.return_vtype # => 26
6658  *
6659  */
6660 static VALUE
6662 {
6663  struct olemethoddata *pmethod;
6664  Data_Get_Struct(self, struct olemethoddata, pmethod);
6665  return ole_method_return_vtype(pmethod->pTypeInfo, pmethod->index);
6666 }
6667 
6668 static VALUE
6669 ole_method_return_type_detail(ITypeInfo *pTypeInfo, UINT method_index)
6670 {
6671  FUNCDESC *pFuncDesc;
6672  HRESULT hr;
6673  VALUE type = rb_ary_new();
6674 
6675  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
6676  if (FAILED(hr))
6677  return type;
6678 
6679  ole_typedesc2val(pTypeInfo, &(pFuncDesc->elemdescFunc.tdesc), type);
6680  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
6681  return type;
6682 }
6683 
6684 /*
6685  * call-seq:
6686  * WIN32OLE_METHOD#return_type_detail
6687  *
6688  * Returns detail information of return value type of method.
6689  * The information is array.
6690  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6691  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6692  * p method.return_type_detail # => ["PTR", "USERDEFINED", "Workbook"]
6693  */
6694 static VALUE
6696 {
6697  struct olemethoddata *pmethod;
6698  Data_Get_Struct(self, struct olemethoddata, pmethod);
6699  return ole_method_return_type_detail(pmethod->pTypeInfo, pmethod->index);
6700 }
6701 
6702 static VALUE
6703 ole_method_invkind(ITypeInfo *pTypeInfo, UINT method_index)
6704 {
6705  FUNCDESC *pFuncDesc;
6706  HRESULT hr;
6707  VALUE invkind;
6708  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
6709  if(FAILED(hr))
6710  ole_raise(hr, eWIN32OLERuntimeError, "failed to GetFuncDesc");
6711  invkind = INT2FIX(pFuncDesc->invkind);
6712  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
6713  return invkind;
6714 }
6715 
6716 static VALUE
6717 ole_method_invoke_kind(ITypeInfo *pTypeInfo, UINT method_index)
6718 {
6719  VALUE type = rb_str_new2("UNKNOWN");
6720  VALUE invkind = ole_method_invkind(pTypeInfo, method_index);
6721  if((FIX2INT(invkind) & INVOKE_PROPERTYGET) &&
6722  (FIX2INT(invkind) & INVOKE_PROPERTYPUT) ) {
6723  type = rb_str_new2("PROPERTY");
6724  } else if(FIX2INT(invkind) & INVOKE_PROPERTYGET) {
6725  type = rb_str_new2("PROPERTYGET");
6726  } else if(FIX2INT(invkind) & INVOKE_PROPERTYPUT) {
6727  type = rb_str_new2("PROPERTYPUT");
6728  } else if(FIX2INT(invkind) & INVOKE_PROPERTYPUTREF) {
6729  type = rb_str_new2("PROPERTYPUTREF");
6730  } else if(FIX2INT(invkind) & INVOKE_FUNC) {
6731  type = rb_str_new2("FUNC");
6732  }
6733  return type;
6734 }
6735 
6736 /*
6737  * call-seq:
6738  * WIN32OLE_MTHOD#invkind
6739  *
6740  * Returns the method invoke kind.
6741  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6742  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6743  * puts method.invkind # => 1
6744  *
6745  */
6746 static VALUE
6748 {
6749  struct olemethoddata *pmethod;
6750  Data_Get_Struct(self, struct olemethoddata, pmethod);
6751  return ole_method_invkind(pmethod->pTypeInfo, pmethod->index);
6752 }
6753 
6754 /*
6755  * call-seq:
6756  * WIN32OLE_METHOD#invoke_kind
6757  *
6758  * Returns the method kind string. The string is "UNKNOWN" or "PROPERTY"
6759  * or "PROPERTY" or "PROPERTYGET" or "PROPERTYPUT" or "PROPERTYPPUTREF"
6760  * or "FUNC".
6761  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6762  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6763  * puts method.invoke_kind # => "FUNC"
6764  */
6765 static VALUE
6767 {
6768  struct olemethoddata *pmethod;
6769  Data_Get_Struct(self, struct olemethoddata, pmethod);
6770  return ole_method_invoke_kind(pmethod->pTypeInfo, pmethod->index);
6771 }
6772 
6773 static VALUE
6774 ole_method_visible(ITypeInfo *pTypeInfo, UINT method_index)
6775 {
6776  FUNCDESC *pFuncDesc;
6777  HRESULT hr;
6778  VALUE visible;
6779  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
6780  if(FAILED(hr))
6781  return Qfalse;
6782  if (pFuncDesc->wFuncFlags & (FUNCFLAG_FRESTRICTED |
6783  FUNCFLAG_FHIDDEN |
6784  FUNCFLAG_FNONBROWSABLE)) {
6785  visible = Qfalse;
6786  } else {
6787  visible = Qtrue;
6788  }
6789  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
6790  return visible;
6791 }
6792 
6793 /*
6794  * call-seq:
6795  * WIN32OLE_METHOD#visible?
6796  *
6797  * Returns true if the method is public.
6798  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6799  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6800  * puts method.visible? # => true
6801  */
6802 static VALUE
6804 {
6805  struct olemethoddata *pmethod;
6806  Data_Get_Struct(self, struct olemethoddata, pmethod);
6807  return ole_method_visible(pmethod->pTypeInfo, pmethod->index);
6808 }
6809 
6810 static VALUE
6811 ole_method_event(ITypeInfo *pTypeInfo, UINT method_index, VALUE method_name)
6812 {
6813  TYPEATTR *pTypeAttr;
6814  HRESULT hr;
6815  WORD i;
6816  int flags;
6817  HREFTYPE href;
6818  ITypeInfo *pRefTypeInfo;
6819  FUNCDESC *pFuncDesc;
6820  BSTR bstr;
6821  VALUE name;
6822  VALUE event = Qfalse;
6823 
6824  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
6825  if (FAILED(hr))
6826  return event;
6827  if(pTypeAttr->typekind != TKIND_COCLASS) {
6828  pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
6829  return event;
6830  }
6831  for (i = 0; i < pTypeAttr->cImplTypes; i++) {
6832  hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
6833  if (FAILED(hr))
6834  continue;
6835 
6836  if (flags & IMPLTYPEFLAG_FSOURCE) {
6837  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
6838  i, &href);
6839  if (FAILED(hr))
6840  continue;
6841  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
6842  href, &pRefTypeInfo);
6843  if (FAILED(hr))
6844  continue;
6845  hr = pRefTypeInfo->lpVtbl->GetFuncDesc(pRefTypeInfo, method_index,
6846  &pFuncDesc);
6847  if (FAILED(hr)) {
6848  OLE_RELEASE(pRefTypeInfo);
6849  continue;
6850  }
6851 
6852  hr = pRefTypeInfo->lpVtbl->GetDocumentation(pRefTypeInfo,
6853  pFuncDesc->memid,
6854  &bstr, NULL, NULL, NULL);
6855  if (FAILED(hr)) {
6856  pRefTypeInfo->lpVtbl->ReleaseFuncDesc(pRefTypeInfo, pFuncDesc);
6857  OLE_RELEASE(pRefTypeInfo);
6858  continue;
6859  }
6860 
6861  name = WC2VSTR(bstr);
6862  pRefTypeInfo->lpVtbl->ReleaseFuncDesc(pRefTypeInfo, pFuncDesc);
6863  OLE_RELEASE(pRefTypeInfo);
6864  if (rb_str_cmp(method_name, name) == 0) {
6865  event = Qtrue;
6866  break;
6867  }
6868  }
6869  }
6870  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
6871  return event;
6872 }
6873 
6874 /*
6875  * call-seq:
6876  * WIN32OLE_METHOD#event?
6877  *
6878  * Returns true if the method is event.
6879  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
6880  * method = WIN32OLE_METHOD.new(tobj, 'SheetActivate')
6881  * puts method.event? # => true
6882  *
6883  */
6884 static VALUE
6886 {
6887  struct olemethoddata *pmethod;
6888  Data_Get_Struct(self, struct olemethoddata, pmethod);
6889  if (!pmethod->pOwnerTypeInfo)
6890  return Qfalse;
6891  return ole_method_event(pmethod->pOwnerTypeInfo,
6892  pmethod->index,
6893  rb_ivar_get(self, rb_intern("name")));
6894 }
6895 
6896 /*
6897  * call-seq:
6898  * WIN32OLE_METHOD#event_interface
6899  *
6900  * Returns event interface name if the method is event.
6901  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
6902  * method = WIN32OLE_METHOD.new(tobj, 'SheetActivate')
6903  * puts method.event_interface # => WorkbookEvents
6904  */
6905 static VALUE
6907 {
6908  BSTR name;
6909  struct olemethoddata *pmethod;
6910  HRESULT hr;
6911  Data_Get_Struct(self, struct olemethoddata, pmethod);
6912  if(folemethod_event(self) == Qtrue) {
6913  hr = ole_docinfo_from_type(pmethod->pTypeInfo, &name, NULL, NULL, NULL);
6914  if(SUCCEEDED(hr))
6915  return WC2VSTR(name);
6916  }
6917  return Qnil;
6918 }
6919 
6920 static VALUE
6922  ITypeInfo *pTypeInfo,
6923  UINT method_index,
6924  BSTR *name,
6925  BSTR *helpstr,
6926  DWORD *helpcontext,
6927  BSTR *helpfile
6928  )
6929 {
6930  FUNCDESC *pFuncDesc;
6931  HRESULT hr;
6932  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
6933  if (FAILED(hr))
6934  return hr;
6935  hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
6936  name, helpstr,
6937  helpcontext, helpfile);
6938  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
6939  return hr;
6940 }
6941 
6942 static VALUE
6943 ole_method_helpstring(ITypeInfo *pTypeInfo, UINT method_index)
6944 {
6945  HRESULT hr;
6946  BSTR bhelpstring;
6947  hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, &bhelpstring,
6948  NULL, NULL);
6949  if (FAILED(hr))
6950  return Qnil;
6951  return WC2VSTR(bhelpstring);
6952 }
6953 
6954 /*
6955  * call-seq:
6956  * WIN32OLE_METHOD#helpstring
6957  *
6958  * Returns help string of OLE method. If the help string is not found,
6959  * then the method returns nil.
6960  * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'IWebBrowser')
6961  * method = WIN32OLE_METHOD.new(tobj, 'Navigate')
6962  * puts method.helpstring # => Navigates to a URL or file.
6963  *
6964  */
6965 static VALUE
6967 {
6968  struct olemethoddata *pmethod;
6969  Data_Get_Struct(self, struct olemethoddata, pmethod);
6970  return ole_method_helpstring(pmethod->pTypeInfo, pmethod->index);
6971 }
6972 
6973 static VALUE
6974 ole_method_helpfile(ITypeInfo *pTypeInfo, UINT method_index)
6975 {
6976  HRESULT hr;
6977  BSTR bhelpfile;
6978  hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, NULL,
6979  NULL, &bhelpfile);
6980  if (FAILED(hr))
6981  return Qnil;
6982  return WC2VSTR(bhelpfile);
6983 }
6984 
6985 /*
6986  * call-seq:
6987  * WIN32OLE_METHOD#helpfile
6988  *
6989  * Returns help file. If help file is not found, then
6990  * the method returns nil.
6991  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
6992  * method = WIN32OLE_METHOD.new(tobj, 'Add')
6993  * puts method.helpfile # => C:\...\VBAXL9.CHM
6994  */
6995 static VALUE
6997 {
6998  struct olemethoddata *pmethod;
6999  Data_Get_Struct(self, struct olemethoddata, pmethod);
7000 
7001  return ole_method_helpfile(pmethod->pTypeInfo, pmethod->index);
7002 }
7003 
7004 static VALUE
7005 ole_method_helpcontext(ITypeInfo *pTypeInfo, UINT method_index)
7006 {
7007  HRESULT hr;
7008  DWORD helpcontext = 0;
7009  hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, NULL,
7010  &helpcontext, NULL);
7011  if (FAILED(hr))
7012  return Qnil;
7013  return INT2FIX(helpcontext);
7014 }
7015 
7016 /*
7017  * call-seq:
7018  * WIN32OLE_METHOD#helpcontext
7019  *
7020  * Returns help context.
7021  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
7022  * method = WIN32OLE_METHOD.new(tobj, 'Add')
7023  * puts method.helpcontext # => 65717
7024  */
7025 static VALUE
7027 {
7028  struct olemethoddata *pmethod;
7029  Data_Get_Struct(self, struct olemethoddata, pmethod);
7030  return ole_method_helpcontext(pmethod->pTypeInfo, pmethod->index);
7031 }
7032 
7033 static VALUE
7034 ole_method_dispid(ITypeInfo *pTypeInfo, UINT method_index)
7035 {
7036  FUNCDESC *pFuncDesc;
7037  HRESULT hr;
7038  VALUE dispid = Qnil;
7039  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7040  if (FAILED(hr))
7041  return dispid;
7042  dispid = INT2NUM(pFuncDesc->memid);
7043  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7044  return dispid;
7045 }
7046 
7047 /*
7048  * call-seq:
7049  * WIN32OLE_METHOD#dispid
7050  *
7051  * Returns dispatch ID.
7052  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
7053  * method = WIN32OLE_METHOD.new(tobj, 'Add')
7054  * puts method.dispid # => 181
7055  */
7056 static VALUE
7058 {
7059  struct olemethoddata *pmethod;
7060  Data_Get_Struct(self, struct olemethoddata, pmethod);
7061  return ole_method_dispid(pmethod->pTypeInfo, pmethod->index);
7062 }
7063 
7064 static VALUE
7065 ole_method_offset_vtbl(ITypeInfo *pTypeInfo, UINT method_index)
7066 {
7067  FUNCDESC *pFuncDesc;
7068  HRESULT hr;
7069  VALUE offset_vtbl = Qnil;
7070  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7071  if (FAILED(hr))
7072  return offset_vtbl;
7073  offset_vtbl = INT2FIX(pFuncDesc->oVft);
7074  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7075  return offset_vtbl;
7076 }
7077 
7078 /*
7079  * call-seq:
7080  * WIN32OLE_METHOD#offset_vtbl
7081  *
7082  * Returns the offset ov VTBL.
7083  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
7084  * method = WIN32OLE_METHOD.new(tobj, 'Add')
7085  * puts method.offset_vtbl # => 40
7086  */
7087 static VALUE
7089 {
7090  struct olemethoddata *pmethod;
7091  Data_Get_Struct(self, struct olemethoddata, pmethod);
7092  return ole_method_offset_vtbl(pmethod->pTypeInfo, pmethod->index);
7093 }
7094 
7095 static VALUE
7096 ole_method_size_params(ITypeInfo *pTypeInfo, UINT method_index)
7097 {
7098  FUNCDESC *pFuncDesc;
7099  HRESULT hr;
7100  VALUE size_params = Qnil;
7101  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7102  if (FAILED(hr))
7103  return size_params;
7104  size_params = INT2FIX(pFuncDesc->cParams);
7105  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7106  return size_params;
7107 }
7108 
7109 /*
7110  * call-seq:
7111  * WIN32OLE_METHOD#size_params
7112  *
7113  * Returns the size of arguments of the method.
7114  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7115  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7116  * puts method.size_params # => 11
7117  *
7118  */
7119 static VALUE
7121 {
7122  struct olemethoddata *pmethod;
7123  Data_Get_Struct(self, struct olemethoddata, pmethod);
7124  return ole_method_size_params(pmethod->pTypeInfo, pmethod->index);
7125 }
7126 
7127 static VALUE
7128 ole_method_size_opt_params(ITypeInfo *pTypeInfo, UINT method_index)
7129 {
7130  FUNCDESC *pFuncDesc;
7131  HRESULT hr;
7132  VALUE size_opt_params = Qnil;
7133  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7134  if (FAILED(hr))
7135  return size_opt_params;
7136  size_opt_params = INT2FIX(pFuncDesc->cParamsOpt);
7137  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7138  return size_opt_params;
7139 }
7140 
7141 /*
7142  * call-seq:
7143  * WIN32OLE_METHOD#size_opt_params
7144  *
7145  * Returns the size of optional parameters.
7146  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7147  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7148  * puts method.size_opt_params # => 4
7149  */
7150 static VALUE
7152 {
7153  struct olemethoddata *pmethod;
7154  Data_Get_Struct(self, struct olemethoddata, pmethod);
7155  return ole_method_size_opt_params(pmethod->pTypeInfo, pmethod->index);
7156 }
7157 
7158 static VALUE
7159 ole_method_params(ITypeInfo *pTypeInfo, UINT method_index)
7160 {
7161  FUNCDESC *pFuncDesc;
7162  HRESULT hr;
7163  BSTR *bstrs;
7164  UINT len, i;
7165  struct oleparamdata *pparam;
7166  VALUE param;
7167  VALUE params = rb_ary_new();
7168  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7169  if (FAILED(hr))
7170  return params;
7171 
7172  len = 0;
7173  bstrs = ALLOCA_N(BSTR, pFuncDesc->cParams + 1);
7174  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pFuncDesc->memid,
7175  bstrs, pFuncDesc->cParams + 1,
7176  &len);
7177  if (FAILED(hr)) {
7178  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7179  return params;
7180  }
7181  SysFreeString(bstrs[0]);
7182  if (pFuncDesc->cParams > 0) {
7183  for(i = 1; i < len; i++) {
7184  param = Data_Make_Struct(cWIN32OLE_PARAM, struct oleparamdata, 0,
7185  oleparam_free, pparam);
7186  pparam->pTypeInfo = pTypeInfo;
7187  OLE_ADDREF(pTypeInfo);
7188  pparam->method_index = method_index;
7189  pparam->index = i - 1;
7190  rb_ivar_set(param, rb_intern("name"), WC2VSTR(bstrs[i]));
7191  rb_ary_push(params, param);
7192  }
7193  }
7194  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7195  return params;
7196 }
7197 
7198 
7199 /*
7200  * call-seq:
7201  * WIN32OLE_METHOD#params
7202  *
7203  * returns array of WIN32OLE_PARAM object corresponding with method parameters.
7204  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7205  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7206  * p method.params # => [Filename, FileFormat, Password, WriteResPassword,
7207  * ReadOnlyRecommended, CreateBackup, AccessMode,
7208  * ConflictResolution, AddToMru, TextCodepage,
7209  * TextVisualLayout]
7210  */
7211 static VALUE
7213 {
7214  struct olemethoddata *pmethod;
7215  Data_Get_Struct(self, struct olemethoddata, pmethod);
7216  return ole_method_params(pmethod->pTypeInfo, pmethod->index);
7217 }
7218 
7219 /*
7220  * call-seq:
7221  * WIN32OLE_METHOD#inspect -> String
7222  *
7223  * Returns the method name with class name.
7224  *
7225  */
7226 static VALUE
7228 {
7229  return default_inspect(self, "WIN32OLE_METHOD");
7230 }
7231 
7232 /*
7233  * Document-class: WIN32OLE_PARAM
7234  *
7235  * <code>WIN32OLE_PARAM</code> objects represent param information of
7236  * the OLE method.
7237  */
7239 {
7240  struct oleparamdata *pparam;
7241  VALUE obj;
7242  obj = Data_Make_Struct(klass,
7243  struct oleparamdata,
7244  0, oleparam_free, pparam);
7245  pparam->pTypeInfo = NULL;
7246  pparam->method_index = 0;
7247  pparam->index = 0;
7248  return obj;
7249 }
7250 
7251 static VALUE
7252 oleparam_ole_param_from_index(VALUE self, ITypeInfo *pTypeInfo, UINT method_index, int param_index)
7253 {
7254  FUNCDESC *pFuncDesc;
7255  HRESULT hr;
7256  BSTR *bstrs;
7257  UINT len;
7258  struct oleparamdata *pparam;
7259  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7260  if (FAILED(hr))
7261  ole_raise(hr, rb_eRuntimeError, "fail to ITypeInfo::GetFuncDesc");
7262 
7263  len = 0;
7264  bstrs = ALLOCA_N(BSTR, pFuncDesc->cParams + 1);
7265  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pFuncDesc->memid,
7266  bstrs, pFuncDesc->cParams + 1,
7267  &len);
7268  if (FAILED(hr)) {
7269  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7270  ole_raise(hr, rb_eRuntimeError, "fail to ITypeInfo::GetNames");
7271  }
7272  SysFreeString(bstrs[0]);
7273  if (param_index < 1 || len <= (UINT)param_index)
7274  {
7275  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7276  rb_raise(rb_eIndexError, "index of param must be in 1..%d", len);
7277  }
7278 
7279  Data_Get_Struct(self, struct oleparamdata, pparam);
7280  pparam->pTypeInfo = pTypeInfo;
7281  OLE_ADDREF(pTypeInfo);
7282  pparam->method_index = method_index;
7283  pparam->index = param_index - 1;
7284  rb_ivar_set(self, rb_intern("name"), WC2VSTR(bstrs[param_index]));
7285 
7286  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7287  return self;
7288 }
7289 
7290 static VALUE oleparam_ole_param(VALUE self, VALUE olemethod, int n)
7291 {
7292  struct olemethoddata *pmethod;
7293  Data_Get_Struct(olemethod, struct olemethoddata, pmethod);
7294  return oleparam_ole_param_from_index(self, pmethod->pTypeInfo, pmethod->index, n);
7295 }
7296 
7297 static VALUE foleparam_initialize(VALUE self, VALUE olemethod, VALUE n)
7298 {
7299  int idx;
7300  if (!rb_obj_is_kind_of(olemethod, cWIN32OLE_METHOD)) {
7301  rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE_METHOD object");
7302  }
7303  idx = FIX2INT(n);
7304  return oleparam_ole_param(self, olemethod, idx);
7305 }
7306 
7307 /*
7308  * call-seq:
7309  * WIN32OLE_PARAM#name
7310  *
7311  * Returns name.
7312  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7313  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7314  * param1 = method.params[0]
7315  * puts param1.name # => Filename
7316  */
7317 static VALUE
7319 {
7320  return rb_ivar_get(self, rb_intern("name"));
7321 }
7322 
7323 static VALUE
7324 ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
7325 {
7326  FUNCDESC *pFuncDesc;
7327  HRESULT hr;
7328  VALUE type = rb_str_new2("unknown type");
7329  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7330  if (FAILED(hr))
7331  return type;
7332  type = ole_typedesc2val(pTypeInfo,
7333  &(pFuncDesc->lprgelemdescParam[index].tdesc), Qnil);
7334  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7335  return type;
7336 }
7337 
7338 /*
7339  * call-seq:
7340  * WIN32OLE_PARAM#ole_type
7341  *
7342  * Returns OLE type of WIN32OLE_PARAM object(parameter of OLE method).
7343  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7344  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7345  * param1 = method.params[0]
7346  * puts param1.ole_type # => VARIANT
7347  */
7348 static VALUE
7350 {
7351  struct oleparamdata *pparam;
7352  Data_Get_Struct(self, struct oleparamdata, pparam);
7353  return ole_param_ole_type(pparam->pTypeInfo, pparam->method_index,
7354  pparam->index);
7355 }
7356 
7357 static VALUE
7359 {
7360  FUNCDESC *pFuncDesc;
7361  HRESULT hr;
7362  VALUE typedetail = rb_ary_new();
7363  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7364  if (FAILED(hr))
7365  return typedetail;
7366  ole_typedesc2val(pTypeInfo,
7367  &(pFuncDesc->lprgelemdescParam[index].tdesc), typedetail);
7368  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7369  return typedetail;
7370 }
7371 
7372 /*
7373  * call-seq:
7374  * WIN32OLE_PARAM#ole_type_detail
7375  *
7376  * Returns detail information of type of argument.
7377  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'IWorksheetFunction')
7378  * method = WIN32OLE_METHOD.new(tobj, 'SumIf')
7379  * param1 = method.params[0]
7380  * p param1.ole_type_detail # => ["PTR", "USERDEFINED", "Range"]
7381  */
7382 static VALUE
7384 {
7385  struct oleparamdata *pparam;
7386  Data_Get_Struct(self, struct oleparamdata, pparam);
7387  return ole_param_ole_type_detail(pparam->pTypeInfo, pparam->method_index,
7388  pparam->index);
7389 }
7390 
7391 static VALUE
7392 ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT mask)
7393 {
7394  FUNCDESC *pFuncDesc;
7395  HRESULT hr;
7396  VALUE ret = Qfalse;
7397  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7398  if(FAILED(hr))
7399  return ret;
7400  if (V_UNION1((&(pFuncDesc->lprgelemdescParam[index])), paramdesc).wParamFlags &mask)
7401  ret = Qtrue;
7402  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7403  return ret;
7404 }
7405 
7406 /*
7407  * call-seq:
7408  * WIN32OLE_PARAM#input?
7409  *
7410  * Returns true if the parameter is input.
7411  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7412  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7413  * param1 = method.params[0]
7414  * puts param1.input? # => true
7415  */
7417 {
7418  struct oleparamdata *pparam;
7419  Data_Get_Struct(self, struct oleparamdata, pparam);
7420  return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
7421  pparam->index, PARAMFLAG_FIN);
7422 }
7423 
7424 /*
7425  * call-seq:
7426  * WIN32OLE#output?
7427  *
7428  * Returns true if argument is output.
7429  * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'DWebBrowserEvents')
7430  * method = WIN32OLE_METHOD.new(tobj, 'NewWindow')
7431  * method.params.each do |param|
7432  * puts "#{param.name} #{param.output?}"
7433  * end
7434  *
7435  * The result of above script is following:
7436  * URL false
7437  * Flags false
7438  * TargetFrameName false
7439  * PostData false
7440  * Headers false
7441  * Processed true
7442  */
7444 {
7445  struct oleparamdata *pparam;
7446  Data_Get_Struct(self, struct oleparamdata, pparam);
7447  return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
7448  pparam->index, PARAMFLAG_FOUT);
7449 }
7450 
7451 /*
7452  * call-seq:
7453  * WIN32OLE_PARAM#optional?
7454  *
7455  * Returns true if argument is optional.
7456  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7457  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7458  * param1 = method.params[0]
7459  * puts "#{param1.name} #{param1.optional?}" # => Filename true
7460  */
7462 {
7463  struct oleparamdata *pparam;
7464  Data_Get_Struct(self, struct oleparamdata, pparam);
7465  return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
7466  pparam->index, PARAMFLAG_FOPT);
7467 }
7468 
7469 /*
7470  * call-seq:
7471  * WIN32OLE_PARAM#retval?
7472  *
7473  * Returns true if argument is return value.
7474  * tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library',
7475  * 'DirectPlayLobbyConnection')
7476  * method = WIN32OLE_METHOD.new(tobj, 'GetPlayerShortName')
7477  * param = method.params[0]
7478  * puts "#{param.name} #{param.retval?}" # => name true
7479  */
7481 {
7482  struct oleparamdata *pparam;
7483  Data_Get_Struct(self, struct oleparamdata, pparam);
7484  return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
7485  pparam->index, PARAMFLAG_FRETVAL);
7486 }
7487 
7488 static VALUE
7490 {
7491  FUNCDESC *pFuncDesc;
7492  ELEMDESC *pElemDesc;
7493  PARAMDESCEX * pParamDescEx;
7494  HRESULT hr;
7495  USHORT wParamFlags;
7496  USHORT mask = PARAMFLAG_FOPT|PARAMFLAG_FHASDEFAULT;
7497  VALUE defval = Qnil;
7498  hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
7499  if (FAILED(hr))
7500  return defval;
7501  pElemDesc = &pFuncDesc->lprgelemdescParam[index];
7502  wParamFlags = V_UNION1(pElemDesc, paramdesc).wParamFlags;
7503  if ((wParamFlags & mask) == mask) {
7504  pParamDescEx = V_UNION1(pElemDesc, paramdesc).pparamdescex;
7505  defval = ole_variant2val(&pParamDescEx->varDefaultValue);
7506  }
7507  pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
7508  return defval;
7509 }
7510 
7511 /*
7512  * call-seq:
7513  * WIN32OLE_PARAM#default
7514  *
7515  * Returns default value. If the default value does not exist,
7516  * this method returns nil.
7517  * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
7518  * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
7519  * method.params.each do |param|
7520  * if param.default
7521  * puts "#{param.name} (= #{param.default})"
7522  * else
7523  * puts "#{param}"
7524  * end
7525  * end
7526  *
7527  * The above script result is following:
7528  * Filename
7529  * FileFormat
7530  * Password
7531  * WriteResPassword
7532  * ReadOnlyRecommended
7533  * CreateBackup
7534  * AccessMode (= 1)
7535  * ConflictResolution
7536  * AddToMru
7537  * TextCodepage
7538  * TextVisualLayout
7539  */
7541 {
7542  struct oleparamdata *pparam;
7543  Data_Get_Struct(self, struct oleparamdata, pparam);
7544  return ole_param_default(pparam->pTypeInfo, pparam->method_index,
7545  pparam->index);
7546 }
7547 
7548 /*
7549  * call-seq:
7550  * WIN32OLE_PARAM#inspect -> String
7551  *
7552  * Returns the parameter name with class name. If the parameter has default value,
7553  * then returns name=value string with class name.
7554  *
7555  */
7556 static VALUE
7558 {
7559  VALUE detail = foleparam_name(self);
7560  VALUE defval = foleparam_default(self);
7561  if (defval != Qnil) {
7562  rb_str_cat2(detail, "=");
7563  rb_str_concat(detail, rb_funcall(defval, rb_intern("inspect"), 0));
7564  }
7565  return make_inspect("WIN32OLE_PARAM", detail);
7566 }
7567 
7568 /*
7569  * Document-class: WIN32OLE_EVENT
7570  *
7571  * <code>WIN32OLE_EVENT</code> objects controls OLE event.
7572  */
7573 
7576 
7577 void EVENTSINK_Destructor(PIEVENTSINKOBJ);
7578 
7579 STDMETHODIMP
7581  PEVENTSINK pEV,
7582  REFIID iid,
7583  LPVOID* ppv
7584  ) {
7585  if (IsEqualIID(iid, &IID_IUnknown) ||
7586  IsEqualIID(iid, &IID_IDispatch) ||
7587  IsEqualIID(iid, &((PIEVENTSINKOBJ)pEV)->m_iid)) {
7588  *ppv = pEV;
7589  }
7590  else {
7591  *ppv = NULL;
7592  return E_NOINTERFACE;
7593  }
7594  ((LPUNKNOWN)*ppv)->lpVtbl->AddRef((LPUNKNOWN)*ppv);
7595  return NOERROR;
7596 }
7597 
7600  PEVENTSINK pEV
7601  ){
7602  PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
7603  return ++pEVObj->m_cRef;
7604 }
7605 
7606 STDMETHODIMP_(ULONG) EVENTSINK_Release(
7607  PEVENTSINK pEV
7608  ) {
7609  PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
7610  --pEVObj->m_cRef;
7611  if(pEVObj->m_cRef != 0)
7612  return pEVObj->m_cRef;
7613  EVENTSINK_Destructor(pEVObj);
7614  return 0;
7615 }
7616 
7618  PEVENTSINK pEV,
7619  UINT *pct
7620  ) {
7621  *pct = 0;
7622  return NOERROR;
7623 }
7624 
7626  PEVENTSINK pEV,
7627  UINT info,
7628  LCID lcid,
7629  ITypeInfo **pInfo
7630  ) {
7631  *pInfo = NULL;
7632  return DISP_E_BADINDEX;
7633 }
7634 
7636  PEVENTSINK pEventSink,
7637  REFIID riid,
7638  OLECHAR **szNames,
7639  UINT cNames,
7640  LCID lcid,
7641  DISPID *pDispID
7642  ) {
7643  ITypeInfo *pTypeInfo;
7644  PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
7645  pTypeInfo = pEV->pTypeInfo;
7646  if (pTypeInfo) {
7647  return pTypeInfo->lpVtbl->GetIDsOfNames(pTypeInfo, szNames, cNames, pDispID);
7648  }
7649  return DISP_E_UNKNOWNNAME;
7650 }
7651 
7652 static long
7654 {
7655  VALUE event;
7656  VALUE def_event;
7657  VALUE event_name;
7658  long i, len;
7659  long ret = -1;
7660  def_event = Qnil;
7661  len = RARRAY_LEN(ary);
7662  for(i = 0; i < len; i++) {
7663  event = rb_ary_entry(ary, i);
7664  event_name = rb_ary_entry(event, 1);
7665  if(NIL_P(event_name) && NIL_P(ev)) {
7666  ret = i;
7667  break;
7668  }
7669  else if (TYPE(ev) == T_STRING &&
7670  TYPE(event_name) == T_STRING &&
7671  rb_str_cmp(ev, event_name) == 0) {
7672  ret = i;
7673  break;
7674  }
7675  }
7676  return ret;
7677 }
7678 
7679 static VALUE
7680 ole_search_event(VALUE ary, VALUE ev, BOOL *is_default)
7681 {
7682  VALUE event;
7683  VALUE def_event;
7684  VALUE event_name;
7685  int i, len;
7686  *is_default = FALSE;
7687  def_event = Qnil;
7688  len = RARRAY_LEN(ary);
7689  for(i = 0; i < len; i++) {
7690  event = rb_ary_entry(ary, i);
7691  event_name = rb_ary_entry(event, 1);
7692  if(NIL_P(event_name)) {
7693  *is_default = TRUE;
7694  def_event = event;
7695  }
7696  else if (rb_str_cmp(ev, event_name) == 0) {
7697  *is_default = FALSE;
7698  return event;
7699  }
7700  }
7701  return def_event;
7702 }
7703 static VALUE
7704 ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler)
7705 {
7706  VALUE mid;
7707 
7708  *is_default_handler = FALSE;
7709  mid = rb_to_id(rb_sprintf("on%s", StringValuePtr(ev)));
7710  if (rb_respond_to(handler, mid)) {
7711  return mid;
7712  }
7713  mid = rb_intern("method_missing");
7714  if (rb_respond_to(handler, mid)) {
7715  *is_default_handler = TRUE;
7716  return mid;
7717  }
7718  return Qnil;
7719 }
7720 
7721 static void
7723 {
7724  long at = -1;
7725  at = ole_search_event_at(ary, ev);
7726  if (at >= 0) {
7727  rb_ary_delete_at(ary, at);
7728  }
7729 }
7730 
7731 static void
7732 hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams)
7733 {
7734  BSTR *bstrs;
7735  HRESULT hr;
7736  UINT len, i;
7737  VARIANT *pvar;
7738  VALUE val;
7739  VALUE key;
7740  len = 0;
7741  bstrs = ALLOCA_N(BSTR, pdispparams->cArgs + 1);
7742  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
7743  bstrs, pdispparams->cArgs + 1,
7744  &len);
7745  if (FAILED(hr))
7746  return;
7747 
7748  for (i = 0; i < len - 1; i++) {
7749  key = WC2VSTR(bstrs[i + 1]);
7750  val = rb_hash_aref(hash, INT2FIX(i));
7751  if (val == Qnil)
7752  val = rb_hash_aref(hash, key);
7753  if (val == Qnil)
7754  val = rb_hash_aref(hash, rb_str_intern(key));
7755  pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
7756  ole_val2ptr_variant(val, pvar);
7757  }
7758 }
7759 
7760 static VALUE
7762 {
7763  VALUE ret = Qnil;
7764  ret = rb_hash_aref(hash, rb_str_new2("return"));
7765  if (ret == Qnil)
7766  ret = rb_hash_aref(hash, rb_str_intern(rb_str_new2("return")));
7767  return ret;
7768 }
7769 
7770 static void
7771 ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams)
7772 {
7773  int i;
7774  VALUE v;
7775  VARIANT *pvar;
7776  for(i = 0; i < RARRAY_LEN(ary) && (unsigned int) i < pdispparams->cArgs; i++) {
7777  v = rb_ary_entry(ary, i);
7778  pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
7779  ole_val2ptr_variant(v, pvar);
7780  }
7781 }
7782 
7783 static VALUE
7785 {
7786  VALUE *parg = (VALUE *)arg;
7787  VALUE handler = parg[0];
7788  VALUE mid = parg[1];
7789  VALUE args = parg[2];
7790  return rb_apply(handler, mid, args);
7791 }
7792 
7793 static VALUE
7795 {
7796 
7797  VALUE error;
7798  VALUE e = rb_errinfo();
7799  VALUE bt = rb_funcall(e, rb_intern("backtrace"), 0);
7800  VALUE msg = rb_funcall(e, rb_intern("message"), 0);
7801  bt = rb_ary_entry(bt, 0);
7802  error = rb_sprintf("%s: %s (%s)\n", StringValuePtr(bt), StringValuePtr(msg), rb_obj_classname(e));
7804  rb_backtrace();
7805  ruby_finalize();
7806  exit(-1);
7807 
7808  return Qnil;
7809 }
7810 
7811 STDMETHODIMP EVENTSINK_Invoke(
7812  PEVENTSINK pEventSink,
7813  DISPID dispid,
7814  REFIID riid,
7815  LCID lcid,
7816  WORD wFlags,
7817  DISPPARAMS *pdispparams,
7818  VARIANT *pvarResult,
7819  EXCEPINFO *pexcepinfo,
7820  UINT *puArgErr
7821  ) {
7822 
7823  HRESULT hr;
7824  BSTR bstr;
7825  unsigned int count;
7826  unsigned int i;
7827  ITypeInfo *pTypeInfo;
7828  VARIANT *pvar;
7829  VALUE ary, obj, event, args, outargv, ev, result;
7830  VALUE handler = Qnil;
7831  VALUE arg[3];
7832  VALUE mid;
7833  VALUE is_outarg = Qfalse;
7834  BOOL is_default_handler = FALSE;
7835  int state;
7836 
7837  PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
7838  pTypeInfo = pEV->pTypeInfo;
7839  obj = evs_entry(pEV->m_event_id);
7840  if (!rb_obj_is_kind_of(obj, cWIN32OLE_EVENT)) {
7841  return NOERROR;
7842  }
7843 
7844  ary = rb_ivar_get(obj, id_events);
7845  if (NIL_P(ary) || TYPE(ary) != T_ARRAY) {
7846  return NOERROR;
7847  }
7848  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
7849  &bstr, 1, &count);
7850  if (FAILED(hr)) {
7851  return NOERROR;
7852  }
7853  ev = WC2VSTR(bstr);
7854  event = ole_search_event(ary, ev, &is_default_handler);
7855  if (TYPE(event) == T_ARRAY) {
7856  handler = rb_ary_entry(event, 0);
7857  mid = rb_intern("call");
7858  is_outarg = rb_ary_entry(event, 3);
7859  } else {
7860  handler = rb_ivar_get(obj, rb_intern("handler"));
7861  if (handler == Qnil) {
7862  return NOERROR;
7863  }
7864  mid = ole_search_handler_method(handler, ev, &is_default_handler);
7865  }
7866  if (handler == Qnil || mid == Qnil) {
7867  return NOERROR;
7868  }
7869 
7870  args = rb_ary_new();
7871  if (is_default_handler) {
7872  rb_ary_push(args, ev);
7873  }
7874 
7875  /* make argument of event handler */
7876  for (i = 0; i < pdispparams->cArgs; ++i) {
7877  pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
7878  rb_ary_push(args, ole_variant2val(pvar));
7879  }
7880  outargv = Qnil;
7881  if (is_outarg == Qtrue) {
7882  outargv = rb_ary_new();
7883  rb_ary_push(args, outargv);
7884  }
7885 
7886  /*
7887  * if exception raised in event callback,
7888  * then you receive cfp consistency error.
7889  * to avoid this error we use begin rescue end.
7890  * and the exception raised then error message print
7891  * and exit ruby process by Win32OLE itself.
7892  */
7893  arg[0] = handler;
7894  arg[1] = mid;
7895  arg[2] = args;
7896  result = rb_protect(exec_callback, (VALUE)arg, &state);
7897  if (state != 0) {
7899  }
7900  if(TYPE(result) == T_HASH) {
7901  hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams);
7902  result = hash2result(result);
7903  }else if (is_outarg == Qtrue && TYPE(outargv) == T_ARRAY) {
7904  ary2ptr_dispparams(outargv, pdispparams);
7905  }
7906 
7907  if (pvarResult) {
7908  VariantInit(pvarResult);
7909  ole_val2variant(result, pvarResult);
7910  }
7911 
7912  return NOERROR;
7913 }
7914 
7915 PIEVENTSINKOBJ
7917  PIEVENTSINKOBJ pEv;
7918  if (!g_IsEventSinkVtblInitialized) {
7920  vtEventSink.AddRef = EVENTSINK_AddRef;
7921  vtEventSink.Release = EVENTSINK_Release;
7922  vtEventSink.Invoke = EVENTSINK_Invoke;
7923  vtEventSink.GetIDsOfNames = EVENTSINK_GetIDsOfNames;
7924  vtEventSink.GetTypeInfoCount = EVENTSINK_GetTypeInfoCount;
7925  vtEventSink.GetTypeInfo = EVENTSINK_GetTypeInfo;
7926 
7927  g_IsEventSinkVtblInitialized = TRUE;
7928  }
7929  pEv = ALLOC_N(IEVENTSINKOBJ, 1);
7930  if(pEv == NULL) return NULL;
7931  pEv->lpVtbl = &vtEventSink;
7932  pEv->m_cRef = 0;
7933  pEv->m_event_id = 0;
7934  pEv->pTypeInfo = NULL;
7935  return pEv;
7936 }
7937 
7939  PIEVENTSINKOBJ pEVObj
7940  ) {
7941  if(pEVObj != NULL) {
7942  OLE_RELEASE(pEVObj->pTypeInfo);
7943  free(pEVObj);
7944  pEVObj = NULL;
7945  }
7946 }
7947 
7948 static HRESULT
7949 find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo)
7950 {
7951  HRESULT hr;
7952  IDispatch *pDispatch;
7953  ITypeInfo *pTypeInfo;
7954  ITypeLib *pTypeLib;
7955  TYPEATTR *pTypeAttr;
7956  HREFTYPE RefType;
7957  ITypeInfo *pImplTypeInfo;
7958  TYPEATTR *pImplTypeAttr;
7959 
7960  struct oledata *pole;
7961  unsigned int index;
7962  unsigned int count;
7963  int type;
7964  BSTR bstr;
7965  char *pstr;
7966 
7967  BOOL is_found = FALSE;
7968  LCID lcid = cWIN32OLE_lcid;
7969 
7970  OLEData_Get_Struct(ole, pole);
7971 
7972  pDispatch = pole->pDispatch;
7973 
7974  hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo);
7975  if (FAILED(hr))
7976  return hr;
7977 
7978  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo,
7979  &pTypeLib,
7980  &index);
7981  OLE_RELEASE(pTypeInfo);
7982  if (FAILED(hr))
7983  return hr;
7984 
7985  if (!pitf) {
7986  hr = pTypeLib->lpVtbl->GetTypeInfoOfGuid(pTypeLib,
7987  piid,
7988  ppTypeInfo);
7989  OLE_RELEASE(pTypeLib);
7990  return hr;
7991  }
7992  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
7993  for (index = 0; index < count; index++) {
7994  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib,
7995  index,
7996  &pTypeInfo);
7997  if (FAILED(hr))
7998  break;
7999  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
8000 
8001  if(FAILED(hr)) {
8002  OLE_RELEASE(pTypeInfo);
8003  break;
8004  }
8005  if(pTypeAttr->typekind == TKIND_COCLASS) {
8006  for (type = 0; type < pTypeAttr->cImplTypes; type++) {
8007  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
8008  type,
8009  &RefType);
8010  if (FAILED(hr))
8011  break;
8012  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
8013  RefType,
8014  &pImplTypeInfo);
8015  if (FAILED(hr))
8016  break;
8017 
8018  hr = pImplTypeInfo->lpVtbl->GetDocumentation(pImplTypeInfo,
8019  -1,
8020  &bstr,
8021  NULL, NULL, NULL);
8022  if (FAILED(hr)) {
8023  OLE_RELEASE(pImplTypeInfo);
8024  break;
8025  }
8026  pstr = ole_wc2mb(bstr);
8027  if (strcmp(pitf, pstr) == 0) {
8028  hr = pImplTypeInfo->lpVtbl->GetTypeAttr(pImplTypeInfo,
8029  &pImplTypeAttr);
8030  if (SUCCEEDED(hr)) {
8031  is_found = TRUE;
8032  *piid = pImplTypeAttr->guid;
8033  if (ppTypeInfo) {
8034  *ppTypeInfo = pImplTypeInfo;
8035  (*ppTypeInfo)->lpVtbl->AddRef((*ppTypeInfo));
8036  }
8037  pImplTypeInfo->lpVtbl->ReleaseTypeAttr(pImplTypeInfo,
8038  pImplTypeAttr);
8039  }
8040  }
8041  free(pstr);
8042  OLE_RELEASE(pImplTypeInfo);
8043  if (is_found || FAILED(hr))
8044  break;
8045  }
8046  }
8047 
8048  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
8049  OLE_RELEASE(pTypeInfo);
8050  if (is_found || FAILED(hr))
8051  break;
8052  }
8053  OLE_RELEASE(pTypeLib);
8054  if(!is_found)
8055  return E_NOINTERFACE;
8056  return hr;
8057 }
8058 
8059 static HRESULT
8061  ITypeInfo *pTypeInfo,
8062  TYPEATTR *pTypeAttr,
8063  ITypeInfo **pCOTypeInfo,
8064  TYPEATTR **pCOTypeAttr)
8065 {
8066  HRESULT hr = E_NOINTERFACE;
8067  ITypeLib *pTypeLib;
8068  int count;
8069  BOOL found = FALSE;
8070  ITypeInfo *pTypeInfo2;
8071  TYPEATTR *pTypeAttr2;
8072  int flags;
8073  int i,j;
8074  HREFTYPE href;
8075  ITypeInfo *pRefTypeInfo;
8076  TYPEATTR *pRefTypeAttr;
8077 
8078  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, NULL);
8079  if (FAILED(hr)) {
8080  return hr;
8081  }
8082  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
8083  for (i = 0; i < count && !found; i++) {
8084  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo2);
8085  if (FAILED(hr))
8086  continue;
8087  hr = OLE_GET_TYPEATTR(pTypeInfo2, &pTypeAttr2);
8088  if (FAILED(hr)) {
8089  OLE_RELEASE(pTypeInfo2);
8090  continue;
8091  }
8092  if (pTypeAttr2->typekind != TKIND_COCLASS) {
8093  OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
8094  OLE_RELEASE(pTypeInfo2);
8095  continue;
8096  }
8097  for (j = 0; j < pTypeAttr2->cImplTypes && !found; j++) {
8098  hr = pTypeInfo2->lpVtbl->GetImplTypeFlags(pTypeInfo2, j, &flags);
8099  if (FAILED(hr))
8100  continue;
8101  if (!(flags & IMPLTYPEFLAG_FDEFAULT))
8102  continue;
8103  hr = pTypeInfo2->lpVtbl->GetRefTypeOfImplType(pTypeInfo2, j, &href);
8104  if (FAILED(hr))
8105  continue;
8106  hr = pTypeInfo2->lpVtbl->GetRefTypeInfo(pTypeInfo2, href, &pRefTypeInfo);
8107  if (FAILED(hr))
8108  continue;
8109  hr = OLE_GET_TYPEATTR(pRefTypeInfo, &pRefTypeAttr);
8110  if (FAILED(hr)) {
8111  OLE_RELEASE(pRefTypeInfo);
8112  continue;
8113  }
8114  if (IsEqualGUID(&(pTypeAttr->guid), &(pRefTypeAttr->guid))) {
8115  found = TRUE;
8116  }
8117  }
8118  if (!found) {
8119  OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
8120  OLE_RELEASE(pTypeInfo2);
8121  }
8122  }
8123  OLE_RELEASE(pTypeLib);
8124  if (found) {
8125  *pCOTypeInfo = pTypeInfo2;
8126  *pCOTypeAttr = pTypeAttr2;
8127  hr = S_OK;
8128  } else {
8129  hr = E_NOINTERFACE;
8130  }
8131  return hr;
8132 }
8133 
8134 static HRESULT
8136  ITypeInfo *pTypeInfo,
8137  TYPEATTR *pTypeAttr,
8138  ITypeInfo **ppTypeInfo)
8139 {
8140  int i = 0;
8141  HRESULT hr = E_NOINTERFACE;
8142  int flags;
8143  HREFTYPE hRefType;
8144  /* Enumerate all implemented types of the COCLASS */
8145  for (i = 0; i < pTypeAttr->cImplTypes; i++) {
8146  hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
8147  if (FAILED(hr))
8148  continue;
8149 
8150  /*
8151  looking for the [default] [source]
8152  we just hope that it is a dispinterface :-)
8153  */
8154  if ((flags & IMPLTYPEFLAG_FDEFAULT) &&
8155  (flags & IMPLTYPEFLAG_FSOURCE)) {
8156 
8157  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
8158  i, &hRefType);
8159  if (FAILED(hr))
8160  continue;
8161  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
8162  hRefType, ppTypeInfo);
8163  if (SUCCEEDED(hr))
8164  break;
8165  }
8166  }
8167  return hr;
8168 }
8169 
8170 static HRESULT
8171 find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo)
8172 {
8173  HRESULT hr;
8174  IProvideClassInfo2 *pProvideClassInfo2;
8175  IProvideClassInfo *pProvideClassInfo;
8176  void *p;
8177 
8178  IDispatch *pDispatch;
8179  ITypeInfo *pTypeInfo;
8180  ITypeInfo *pTypeInfo2 = NULL;
8181  TYPEATTR *pTypeAttr;
8182  TYPEATTR *pTypeAttr2 = NULL;
8183 
8184  struct oledata *pole;
8185 
8186  OLEData_Get_Struct(ole, pole);
8187  pDispatch = pole->pDispatch;
8188  hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
8189  &IID_IProvideClassInfo2,
8190  &p);
8191  if (SUCCEEDED(hr)) {
8192  pProvideClassInfo2 = p;
8193  hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2,
8194  GUIDKIND_DEFAULT_SOURCE_DISP_IID,
8195  piid);
8196  OLE_RELEASE(pProvideClassInfo2);
8197  if (SUCCEEDED(hr)) {
8198  hr = find_iid(ole, NULL, piid, ppTypeInfo);
8199  }
8200  }
8201  if (SUCCEEDED(hr)) {
8202  return hr;
8203  }
8204  hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
8205  &IID_IProvideClassInfo,
8206  &p);
8207  if (SUCCEEDED(hr)) {
8208  pProvideClassInfo = p;
8209  hr = pProvideClassInfo->lpVtbl->GetClassInfo(pProvideClassInfo,
8210  &pTypeInfo);
8211  OLE_RELEASE(pProvideClassInfo);
8212  }
8213  if (FAILED(hr)) {
8214  hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, cWIN32OLE_lcid, &pTypeInfo );
8215  }
8216  if (FAILED(hr))
8217  return hr;
8218  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
8219  if (FAILED(hr)) {
8220  OLE_RELEASE(pTypeInfo);
8221  return hr;
8222  }
8223 
8224  *ppTypeInfo = 0;
8225  hr = find_default_source_from_typeinfo(pTypeInfo, pTypeAttr, ppTypeInfo);
8226  if (!*ppTypeInfo) {
8227  hr = find_coclass(pTypeInfo, pTypeAttr, &pTypeInfo2, &pTypeAttr2);
8228  if (SUCCEEDED(hr)) {
8229  hr = find_default_source_from_typeinfo(pTypeInfo2, pTypeAttr2, ppTypeInfo);
8230  OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
8231  OLE_RELEASE(pTypeInfo2);
8232  }
8233  }
8234  OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
8235  OLE_RELEASE(pTypeInfo);
8236  /* Now that would be a bad surprise, if we didn't find it, wouldn't it? */
8237  if (!*ppTypeInfo) {
8238  if (SUCCEEDED(hr))
8239  hr = E_UNEXPECTED;
8240  return hr;
8241  }
8242 
8243  /* Determine IID of default source interface */
8244  hr = (*ppTypeInfo)->lpVtbl->GetTypeAttr(*ppTypeInfo, &pTypeAttr);
8245  if (SUCCEEDED(hr)) {
8246  *piid = pTypeAttr->guid;
8247  (*ppTypeInfo)->lpVtbl->ReleaseTypeAttr(*ppTypeInfo, pTypeAttr);
8248  }
8249  else
8250  OLE_RELEASE(*ppTypeInfo);
8251 
8252  return hr;
8253 
8254 }
8255 
8256 static void
8258 {
8259  if (poleev->pConnectionPoint) {
8260  poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie);
8261  OLE_RELEASE(poleev->pConnectionPoint);
8262  poleev->pConnectionPoint = NULL;
8263  }
8264  free(poleev);
8265 }
8266 
8267 static VALUE
8269 {
8270  VALUE obj;
8271  struct oleeventdata *poleev;
8272  obj = Data_Make_Struct(klass,struct oleeventdata,0,ole_event_free,poleev);
8273  poleev->dwCookie = 0;
8274  poleev->pConnectionPoint = NULL;
8275  poleev->event_id = 0;
8276  return obj;
8277 }
8278 
8279 static VALUE
8281 {
8282 
8283  VALUE ole, itf;
8284  struct oledata *pole;
8285  char *pitf;
8286  HRESULT hr;
8287  IID iid;
8288  ITypeInfo *pTypeInfo = 0;
8289  IDispatch *pDispatch;
8290  IConnectionPointContainer *pContainer;
8291  IConnectionPoint *pConnectionPoint;
8292  IEVENTSINKOBJ *pIEV;
8293  DWORD dwCookie;
8294  struct oleeventdata *poleev;
8295  void *p;
8296 
8297  rb_secure(4);
8298  rb_scan_args(argc, argv, "11", &ole, &itf);
8299 
8300  if (!rb_obj_is_kind_of(ole, cWIN32OLE)) {
8301  rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE object");
8302  }
8303 
8304  if(TYPE(itf) != T_NIL) {
8305  if (rb_safe_level() > 0 && OBJ_TAINTED(itf)) {
8306  rb_raise(rb_eSecurityError, "Insecure Event Creation - %s",
8307  StringValuePtr(itf));
8308  }
8309  SafeStringValue(itf);
8310  pitf = StringValuePtr(itf);
8311  hr = find_iid(ole, pitf, &iid, &pTypeInfo);
8312  }
8313  else {
8314  hr = find_default_source(ole, &iid, &pTypeInfo);
8315  }
8316  if (FAILED(hr)) {
8317  ole_raise(hr, rb_eRuntimeError, "interface not found");
8318  }
8319 
8320  OLEData_Get_Struct(ole, pole);
8321  pDispatch = pole->pDispatch;
8322  hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
8323  &IID_IConnectionPointContainer,
8324  &p);
8325  if (FAILED(hr)) {
8326  OLE_RELEASE(pTypeInfo);
8328  "failed to query IConnectionPointContainer");
8329  }
8330  pContainer = p;
8331 
8332  hr = pContainer->lpVtbl->FindConnectionPoint(pContainer,
8333  &iid,
8334  &pConnectionPoint);
8335  OLE_RELEASE(pContainer);
8336  if (FAILED(hr)) {
8337  OLE_RELEASE(pTypeInfo);
8338  ole_raise(hr, rb_eRuntimeError, "failed to query IConnectionPoint");
8339  }
8340  pIEV = EVENTSINK_Constructor();
8341  pIEV->m_iid = iid;
8342  hr = pConnectionPoint->lpVtbl->Advise(pConnectionPoint,
8343  (IUnknown*)pIEV,
8344  &dwCookie);
8345  if (FAILED(hr)) {
8346  ole_raise(hr, rb_eRuntimeError, "Advise Error");
8347  }
8348 
8349  Data_Get_Struct(self, struct oleeventdata, poleev);
8350  pIEV->m_event_id
8351  = NUM2INT(evs_length());
8352  pIEV->pTypeInfo = pTypeInfo;
8353  poleev->dwCookie = dwCookie;
8355  poleev->event_id = pIEV->m_event_id;
8356 
8357  return self;
8358 }
8359 
8360 /*
8361  * call-seq:
8362  * WIN32OLE_EVENT.new(ole, event) #=> WIN32OLE_EVENT object.
8363  *
8364  * Returns OLE event object.
8365  * The first argument specifies WIN32OLE object.
8366  * The second argument specifies OLE event name.
8367  * ie = WIN32OLE.new('InternetExplorer.Application')
8368  * ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
8369  */
8370 static VALUE
8372 {
8373  ev_advise(argc, argv, self);
8374  evs_push(self);
8375  rb_ivar_set(self, id_events, rb_ary_new());
8376  fev_set_handler(self, Qnil);
8377  return self;
8378 }
8379 
8380 /*
8381  * call-seq:
8382  * WIN32OLE_EVENT.message_loop
8383  *
8384  * Translates and dispatches Windows message.
8385  */
8386 static VALUE
8388 {
8389  ole_msg_loop();
8390  return Qnil;
8391 }
8392 
8393 
8394 static void
8396 {
8397  VALUE events = rb_ivar_get(obj, id_events);
8398  if (NIL_P(events) || TYPE(events) != T_ARRAY) {
8399  events = rb_ary_new();
8400  rb_ivar_set(obj, id_events, events);
8401  }
8402  ole_delete_event(events, event);
8403  rb_ary_push(events, data);
8404 }
8405 
8406 static VALUE
8407 ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
8408 {
8409  struct oleeventdata *poleev;
8410  VALUE event, args, data;
8411  Data_Get_Struct(self, struct oleeventdata, poleev);
8412  if (poleev->pConnectionPoint == NULL) {
8413  rb_raise(eWIN32OLERuntimeError, "IConnectionPoint not found. You must call advise at first.");
8414  }
8415  rb_scan_args(argc, argv, "01*", &event, &args);
8416  if(!NIL_P(event)) {
8417  if(TYPE(event) != T_STRING && TYPE(event) != T_SYMBOL) {
8418  rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
8419  }
8420  if (TYPE(event) == T_SYMBOL) {
8421  event = rb_sym_to_s(event);
8422  }
8423  }
8424  data = rb_ary_new3(4, rb_block_proc(), event, args, is_ary_arg);
8425  add_event_call_back(self, event, data);
8426  return Qnil;
8427 }
8428 
8429 /*
8430  * call-seq:
8431  * WIN32OLE_EVENT#on_event([event]){...}
8432  *
8433  * Defines the callback event.
8434  * If argument is omitted, this method defines the callback of all events.
8435  * If you want to modify reference argument in callback, return hash in
8436  * callback. If you want to return value to OLE server as result of callback
8437  * use `return' or :return.
8438  *
8439  * ie = WIN32OLE.new('InternetExplorer.Application')
8440  * ev = WIN32OLE_EVENT.new(ie)
8441  * ev.on_event("NavigateComplete") {|url| puts url}
8442  * ev.on_event() {|ev, *args| puts "#{ev} fired"}
8443  *
8444  * ev.on_event("BeforeNavigate2") {|*args|
8445  * ...
8446  * # set true to BeforeNavigate reference argument `Cancel'.
8447  * # Cancel is 7-th argument of BeforeNavigate,
8448  * # so you can use 6 as key of hash instead of 'Cancel'.
8449  * # The argument is counted from 0.
8450  * # The hash key of 0 means first argument.)
8451  * {:Cancel => true} # or {'Cancel' => true} or {6 => true}
8452  * }
8453  *
8454  * ev.on_event(...) {|*args|
8455  * {:return => 1, :xxx => yyy}
8456  * }
8457  */
8458 static VALUE
8460 {
8461  return ev_on_event(argc, argv, self, Qfalse);
8462 }
8463 
8464 /*
8465  * call-seq:
8466  * WIN32OLE_EVENT#on_event_with_outargs([event]){...}
8467  *
8468  * Defines the callback of event.
8469  * If you want modify argument in callback,
8470  * you could use this method instead of WIN32OLE_EVENT#on_event.
8471  *
8472  * ie = WIN32OLE.new('InternetExplorer.Application')
8473  * ev = WIN32OLE_EVENT.new(ie)
8474  * ev.on_event_with_outargs('BeforeNavigate2') {|*args|
8475  * args.last[6] = true
8476  * }
8477  */
8478 static VALUE
8480 {
8481  return ev_on_event(argc, argv, self, Qtrue);
8482 }
8483 
8484 /*
8485  * call-seq:
8486  * WIN32OLE_EVENT#off_event([event])
8487  *
8488  * removes the callback of event.
8489  *
8490  * ie = WIN32OLE.new('InternetExplorer.Application')
8491  * ev = WIN32OLE_EVENT.new(ie)
8492  * ev.on_event('BeforeNavigate2') {|*args|
8493  * args.last[6] = true
8494  * }
8495  * ...
8496  * ev.off_event('BeforeNavigate2')
8497  * ...
8498  */
8499 static VALUE
8501 {
8502  VALUE event = Qnil;
8503  VALUE events;
8504 
8505  rb_secure(4);
8506  rb_scan_args(argc, argv, "01", &event);
8507  if(!NIL_P(event)) {
8508  if(TYPE(event) != T_STRING && TYPE(event) != T_SYMBOL) {
8509  rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
8510  }
8511  if (TYPE(event) == T_SYMBOL) {
8512  event = rb_sym_to_s(event);
8513  }
8514  }
8515  events = rb_ivar_get(self, id_events);
8516  if (NIL_P(events)) {
8517  return Qnil;
8518  }
8519  ole_delete_event(events, event);
8520  return Qnil;
8521 }
8522 
8523 /*
8524  * call-seq:
8525  * WIN32OLE_EVENT#unadvise -> nil
8526  *
8527  * disconnects OLE server. If this method called, then the WIN32OLE_EVENT object
8528  * does not receive the OLE server event any more.
8529  * This method is trial implementation.
8530  *
8531  * ie = WIN32OLE.new('InternetExplorer.Application')
8532  * ev = WIN32OLE_EVENT.new(ie)
8533  * ev.on_event() {...}
8534  * ...
8535  * ev.unadvise
8536  *
8537  */
8538 static VALUE
8540 {
8541  struct oleeventdata *poleev;
8542  Data_Get_Struct(self, struct oleeventdata, poleev);
8543  if (poleev->pConnectionPoint) {
8544  ole_msg_loop();
8545  evs_delete(poleev->event_id);
8546  poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie);
8547  OLE_RELEASE(poleev->pConnectionPoint);
8548  poleev->pConnectionPoint = NULL;
8549  }
8550  return Qnil;
8551 }
8552 
8553 static VALUE
8555 {
8556  return rb_ary_push(ary_ole_event, ev);
8557 }
8558 
8559 static VALUE
8560 evs_delete(long i)
8561 {
8563  return Qnil;
8564 }
8565 
8566 static VALUE
8567 evs_entry(long i)
8568 {
8569  return rb_ary_entry(ary_ole_event, i);
8570 }
8571 
8572 static VALUE
8574 {
8575  return rb_funcall(ary_ole_event, rb_intern("length"), 0);
8576 }
8577 
8578 /*
8579  * call-seq:
8580  * WIN32OLE_EVENT#handler=
8581  *
8582  * sets event handler object. If handler object has onXXX
8583  * method according to XXX event, then onXXX method is called
8584  * when XXX event occurs.
8585  *
8586  * If handler object has method_missing and there is no
8587  * method according to the event, then method_missing
8588  * called and 1-st argument is event name.
8589  *
8590  * If handler object has onXXX method and there is block
8591  * defined by WIN32OLE_EVENT#on_event('XXX'){},
8592  * then block is executed but handler object method is not called
8593  * when XXX event occurs.
8594  *
8595  * class Handler
8596  * def onStatusTextChange(text)
8597  * puts "StatusTextChanged"
8598  * end
8599  * def onPropertyChange(prop)
8600  * puts "PropertyChanged"
8601  * end
8602  * def method_missing(ev, *arg)
8603  * puts "other event #{ev}"
8604  * end
8605  * end
8606  *
8607  * handler = Handler.new
8608  * ie = WIN32OLE.new('InternetExplorer.Application')
8609  * ev = WIN32OLE_EVENT.new(ie)
8610  * ev.on_event("StatusTextChange") {|*args|
8611  * puts "this block executed."
8612  * puts "handler.onStatusTextChange method is not called."
8613  * }
8614  * ev.handler = handler
8615  *
8616  */
8617 static VALUE
8619 {
8620  return rb_ivar_set(self, rb_intern("handler"), val);
8621 }
8622 
8623 /*
8624  * call-seq:
8625  * WIN32OLE_EVENT#handler
8626  *
8627  * returns handler object.
8628  *
8629  */
8630 static VALUE
8632 {
8633  return rb_ivar_get(self, rb_intern("handler"));
8634 }
8635 
8636 static void
8638 {
8639  VariantClear(&(pvar->realvar));
8640  VariantClear(&(pvar->var));
8641  free(pvar);
8642 }
8643 
8644 static VALUE
8646 {
8647  struct olevariantdata *pvar;
8648  VALUE obj;
8649  ole_initialize();
8650  obj = Data_Make_Struct(klass,struct olevariantdata,0,olevariant_free,pvar);
8651  VariantInit(&(pvar->var));
8652  VariantInit(&(pvar->realvar));
8653  return obj;
8654 }
8655 
8656 /*
8657  * call-seq:
8658  * WIN32OLE_VARIANT.array(ary, vt)
8659  *
8660  * Returns Ruby object wrapping OLE variant whose variant type is VT_ARRAY.
8661  * The first argument should be Array object which specifies dimensions
8662  * and each size of dimensions of OLE array.
8663  * The second argument specifies variant type of the element of OLE array.
8664  *
8665  * The following create 2 dimensions OLE array. The first dimensions size
8666  * is 3, and the second is 4.
8667  *
8668  * ole_ary = WIN32OLE_VARIANT.array([3,4], VT_I4)
8669  * ruby_ary = ole_ary.value # => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
8670  *
8671  */
8672 static VALUE
8674 {
8675  VALUE obj = Qnil;
8676  VARTYPE vt;
8677  struct olevariantdata *pvar;
8678  SAFEARRAYBOUND *psab = NULL;
8679  SAFEARRAY *psa = NULL;
8680  UINT dim = 0;
8681  UINT i = 0;
8682 
8683  ole_initialize();
8684 
8685  vt = NUM2UINT(vvt);
8686  vt = (vt | VT_ARRAY);
8687  Check_Type(elems, T_ARRAY);
8688  obj = folevariant_s_allocate(klass);
8689 
8690  Data_Get_Struct(obj, struct olevariantdata, pvar);
8691  dim = RARRAY_LEN(elems);
8692 
8693  psab = ALLOC_N(SAFEARRAYBOUND, dim);
8694 
8695  if(!psab) {
8696  rb_raise(rb_eRuntimeError, "memory allocation error");
8697  }
8698 
8699  for (i = 0; i < dim; i++) {
8700  psab[i].cElements = FIX2INT(rb_ary_entry(elems, i));
8701  psab[i].lLbound = 0;
8702  }
8703 
8704  psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
8705  if (psa == NULL) {
8706  if (psab) free(psab);
8707  rb_raise(rb_eRuntimeError, "memory allocation error(SafeArrayCreate)");
8708  }
8709 
8710  V_VT(&(pvar->var)) = vt;
8711  if (vt & VT_BYREF) {
8712  V_VT(&(pvar->realvar)) = (vt & ~VT_BYREF);
8713  V_ARRAY(&(pvar->realvar)) = psa;
8714  V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
8715  } else {
8716  V_ARRAY(&(pvar->var)) = psa;
8717  }
8718  if (psab) free(psab);
8719  return obj;
8720 }
8721 
8722 /*
8723  * call-seq:
8724  * WIN32OLE_VARIANT.new(val, vartype) #=> WIN32OLE_VARIANT object.
8725  *
8726  * Returns Ruby object wrapping OLE variant.
8727  * The first argument specifies Ruby object to convert OLE variant variable.
8728  * The second argument specifies VARIANT type.
8729  * In some situation, you need the WIN32OLE_VARIANT object to pass OLE method
8730  *
8731  * shell = WIN32OLE.new("Shell.Application")
8732  * folder = shell.NameSpace("C:\\Windows")
8733  * item = folder.ParseName("tmp.txt")
8734  * # You can't use Ruby String object to call FolderItem.InvokeVerb.
8735  * # Instead, you have to use WIN32OLE_VARIANT object to call the method.
8736  * shortcut = WIN32OLE_VARIANT.new("Create Shortcut(\&S)")
8737  * item.invokeVerb(shortcut)
8738  *
8739  */
8740 static VALUE
8742 {
8743  int len = 0;
8744  VARIANT var;
8745  VALUE val;
8746  VALUE vvt;
8747  VARTYPE vt;
8748  struct olevariantdata *pvar;
8749 
8750  len = RARRAY_LEN(args);
8751  if (len < 1 || len > 3) {
8752  rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", len);
8753  }
8754  VariantInit(&var);
8755  val = rb_ary_entry(args, 0);
8756 
8757  if(!rb_obj_is_kind_of(val, cWIN32OLE) &&
8759  !rb_obj_is_kind_of(val, rb_cTime)) {
8760  switch (TYPE(val)) {
8761  case T_ARRAY:
8762  case T_STRING:
8763  case T_FIXNUM:
8764  case T_BIGNUM:
8765  case T_FLOAT:
8766  case T_TRUE:
8767  case T_FALSE:
8768  case T_NIL:
8769  break;
8770  default:
8771  rb_raise(rb_eTypeError, "can not convert WIN32OLE_VARIANT from type %s",
8772  rb_obj_classname(val));
8773  }
8774  }
8775 
8776  Data_Get_Struct(self, struct olevariantdata, pvar);
8777  if (len == 1) {
8778  ole_val2variant(val, &(pvar->var));
8779  } else {
8780  vvt = rb_ary_entry(args, 1);
8781  vt = NUM2INT(vvt);
8782  ole_val2olevariantdata(val, vt, pvar);
8783  }
8784  vt = V_VT(&pvar->var);
8785  return self;
8786 }
8787 
8788 static SAFEARRAY *
8790 {
8791  struct olevariantdata *pvar;
8792  SAFEARRAY *psa = NULL;
8793  HRESULT hr;
8794  Data_Get_Struct(val, struct olevariantdata, pvar);
8795  if (!(V_VT(&(pvar->var)) & VT_ARRAY)) {
8796  rb_raise(rb_eTypeError, "variant type is not VT_ARRAY.");
8797  }
8798  psa = V_ISBYREF(&(pvar->var)) ? *V_ARRAYREF(&(pvar->var)) : V_ARRAY(&(pvar->var));
8799  if (psa == NULL) {
8800  return psa;
8801  }
8802  hr = SafeArrayLock(psa);
8803  if (FAILED(hr)) {
8804  ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayLock");
8805  }
8806  return psa;
8807 }
8808 
8809 static long *
8810 ary2safe_array_index(int ary_size, VALUE *ary, SAFEARRAY *psa)
8811 {
8812  long dim;
8813  long *pid;
8814  long i;
8815  dim = SafeArrayGetDim(psa);
8816  if (dim != ary_size) {
8817  rb_raise(rb_eArgError, "unmatch number of indices");
8818  }
8819  pid = ALLOC_N(long, dim);
8820  if (pid == NULL) {
8821  rb_raise(rb_eRuntimeError, "failed to allocate memory for indices");
8822  }
8823  for (i = 0; i < dim; i++) {
8824  pid[i] = NUM2INT(ary[i]);
8825  }
8826  return pid;
8827 }
8828 
8829 static void
8830 unlock_safe_array(SAFEARRAY *psa)
8831 {
8832  HRESULT hr;
8833  hr = SafeArrayUnlock(psa);
8834  if (FAILED(hr)) {
8835  ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayUnlock");
8836  }
8837 }
8838 
8839 /*
8840  * call-seq:
8841  * WIN32OLE_VARIANT[i,j,...] #=> element of OLE array.
8842  *
8843  * Returns the element of WIN32OLE_VARIANT object(OLE array).
8844  * This method is available only when the variant type of
8845  * WIN32OLE_VARIANT object is VT_ARRAY.
8846  *
8847  * REMARK:
8848  * The all indicies should be 0 or natural number and
8849  * lower than or equal to max indicies.
8850  * (This point is different with Ruby Array indicies.)
8851  *
8852  * obj = WIN32OLE_VARIANT.new([[1,2,3],[4,5,6]])
8853  * p obj[0,0] # => 1
8854  * p obj[1,0] # => 4
8855  * p obj[2,0] # => WIN32OLERuntimeError
8856  * p obj[0, -1] # => WIN32OLERuntimeError
8857  *
8858  */
8859 static VALUE
8861 {
8862  struct olevariantdata *pvar;
8863  SAFEARRAY *psa;
8864  VALUE val = Qnil;
8865  VARIANT variant;
8866  long *pid;
8867  HRESULT hr;
8868 
8869  Data_Get_Struct(self, struct olevariantdata, pvar);
8870  if (!V_ISARRAY(&(pvar->var))) {
8872  "`[]' is not available for this variant type object");
8873  }
8874  psa = get_locked_safe_array(self);
8875  if (psa == NULL) {
8876  return val;
8877  }
8878 
8879  pid = ary2safe_array_index(argc, argv, psa);
8880 
8881  VariantInit(&variant);
8882  V_VT(&variant) = (V_VT(&(pvar->var)) & ~VT_ARRAY) | VT_BYREF;
8883  hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
8884  if (FAILED(hr)) {
8885  ole_raise(hr, eWIN32OLERuntimeError, "failed to SafeArrayPtrOfIndex");
8886  }
8887  val = ole_variant2val(&variant);
8888 
8889  unlock_safe_array(psa);
8890  if (pid) free(pid);
8891  return val;
8892 }
8893 
8894 static VOID *
8895 val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt)
8896 {
8897  VOID *p = NULL;
8898  HRESULT hr = S_OK;
8899  ole_val2variant_ex(val, var, vt);
8900  if ((vt & ~VT_BYREF) == VT_VARIANT) {
8901  p = var;
8902  } else {
8903  if ( (vt & ~VT_BYREF) != V_VT(var)) {
8904  hr = VariantChangeTypeEx(var, var,
8905  cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF));
8906  if (FAILED(hr)) {
8907  ole_raise(hr, rb_eRuntimeError, "failed to change type");
8908  }
8909  }
8910  p = get_ptr_of_variant(var);
8911  }
8912  if (p == NULL) {
8913  rb_raise(rb_eRuntimeError, "failed to get pointer of variant");
8914  }
8915  return p;
8916 }
8917 
8918 /*
8919  * call-seq:
8920  * WIN32OLE_VARIANT[i,j,...] = val #=> set the element of OLE array
8921  *
8922  * Set the element of WIN32OLE_VARIANT object(OLE array) to val.
8923  * This method is available only when the variant type of
8924  * WIN32OLE_VARIANT object is VT_ARRAY.
8925  *
8926  * REMARK:
8927  * The all indicies should be 0 or natural number and
8928  * lower than or equal to max indicies.
8929  * (This point is different with Ruby Array indicies.)
8930  *
8931  * obj = WIN32OLE_VARIANT.new([[1,2,3],[4,5,6]])
8932  * obj[0,0] = 7
8933  * obj[1,0] = 8
8934  * p obj.value # => [[7,2,3], [8,5,6]]
8935  * obj[2,0] = 9 # => WIN32OLERuntimeError
8936  * obj[0, -1] = 9 # => WIN32OLERuntimeError
8937  *
8938  */
8939 static VALUE
8941 {
8942  struct olevariantdata *pvar;
8943  SAFEARRAY *psa;
8944  VARIANT var;
8945  VARTYPE vt;
8946  long *pid;
8947  HRESULT hr;
8948  VOID *p = NULL;
8949 
8950  Data_Get_Struct(self, struct olevariantdata, pvar);
8951  if (!V_ISARRAY(&(pvar->var))) {
8953  "`[]' is not available for this variant type object");
8954  }
8955  psa = get_locked_safe_array(self);
8956  if (psa == NULL) {
8957  rb_raise(rb_eRuntimeError, "failed to get SafeArray pointer");
8958  }
8959 
8960  pid = ary2safe_array_index(argc-1, argv, psa);
8961 
8962  VariantInit(&var);
8963  vt = (V_VT(&(pvar->var)) & ~VT_ARRAY);
8964  p = val2variant_ptr(argv[argc-1], &var, vt);
8965  if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
8966  (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
8967  rb_raise(eWIN32OLERuntimeError, "argument does not have IDispatch or IUnknown Interface");
8968  }
8969  hr = SafeArrayPutElement(psa, pid, p);
8970  if (FAILED(hr)) {
8971  ole_raise(hr, eWIN32OLERuntimeError, "failed to SafeArrayPutElement");
8972  }
8973 
8974  unlock_safe_array(psa);
8975  if (pid) free(pid);
8976  return argv[argc-1];
8977 }
8978 
8979 /*
8980  * call-seq:
8981  * WIN32OLE_VARIANT.value #=> Ruby object.
8982  *
8983  * Returns Ruby object value from OLE variant.
8984  * obj = WIN32OLE_VARIANT.new(1, WIN32OLE::VARIANT::VT_BSTR)
8985  * obj.value # => "1" (not Fixnum object, but String object "1")
8986  *
8987  */
8988 static VALUE
8990 {
8991  struct olevariantdata *pvar;
8992  VALUE val = Qnil;
8993  VARTYPE vt;
8994  int dim;
8995  SAFEARRAY *psa;
8996  Data_Get_Struct(self, struct olevariantdata, pvar);
8997 
8998  val = ole_variant2val(&(pvar->var));
8999  vt = V_VT(&(pvar->var));
9000 
9001  if ((vt & ~VT_BYREF) == (VT_UI1|VT_ARRAY)) {
9002  if (vt & VT_BYREF) {
9003  psa = *V_ARRAYREF(&(pvar->var));
9004  } else {
9005  psa = V_ARRAY(&(pvar->var));
9006  }
9007  if (!psa) {
9008  return val;
9009  }
9010  dim = SafeArrayGetDim(psa);
9011  if (dim == 1) {
9012  val = rb_funcall(val, rb_intern("pack"), 1, rb_str_new2("C*"));
9013  }
9014  }
9015  return val;
9016 }
9017 
9018 /*
9019  * call-seq:
9020  * WIN32OLE_VARIANT.vartype #=> OLE variant type.
9021  *
9022  * Returns OLE variant type.
9023  * obj = WIN32OLE_VARIANT.new("string")
9024  * obj.vartype # => WIN32OLE::VARIANT::VT_BSTR
9025  *
9026  */
9027 static VALUE
9029 {
9030  struct olevariantdata *pvar;
9031  Data_Get_Struct(self, struct olevariantdata, pvar);
9032  return INT2FIX(V_VT(&pvar->var));
9033 }
9034 
9035 /*
9036  * call-seq:
9037  * WIN32OLE_VARIANT.value = val #=> set WIN32OLE_VARIANT value to val.
9038  *
9039  * Sets variant value to val. If the val type does not match variant value
9040  * type(vartype), then val is changed to match variant value type(vartype)
9041  * before setting val.
9042  * Thie method is not available when vartype is VT_ARRAY(except VT_UI1|VT_ARRAY).
9043  * If the vartype is VT_UI1|VT_ARRAY, the val should be String object.
9044  *
9045  * obj = WIN32OLE_VARIANT.new(1) # obj.vartype is WIN32OLE::VARIANT::VT_I4
9046  * obj.value = 3.2 # 3.2 is changed to 3 when setting value.
9047  * p obj.value # => 3
9048  */
9049 static VALUE
9051 {
9052  struct olevariantdata *pvar;
9053  VARTYPE vt;
9054  Data_Get_Struct(self, struct olevariantdata, pvar);
9055  vt = V_VT(&(pvar->var));
9056  if (V_ISARRAY(&(pvar->var)) && ((vt & ~VT_BYREF) != (VT_UI1|VT_ARRAY) || TYPE(val) != T_STRING)) {
9058  "`value=' is not available for this variant type object");
9059  }
9060  ole_val2olevariantdata(val, vt, pvar);
9061  return Qnil;
9062 }
9063 
9064 static void
9066 {
9067  enc2cp_table = st_init_numtable();
9068 }
9069 
9070 static void
9072 {
9073  st_free_table(enc2cp_table);
9074 }
9075 
9076 void
9078 {
9081  id_events = rb_intern("events");
9082 
9083  com_vtbl.QueryInterface = QueryInterface;
9084  com_vtbl.AddRef = AddRef;
9085  com_vtbl.Release = Release;
9086  com_vtbl.GetTypeInfoCount = GetTypeInfoCount;
9087  com_vtbl.GetTypeInfo = GetTypeInfo;
9088  com_vtbl.GetIDsOfNames = GetIDsOfNames;
9089  com_vtbl.Invoke = Invoke;
9090 
9091  message_filter.QueryInterface = mf_QueryInterface;
9092  message_filter.AddRef = mf_AddRef;
9093  message_filter.Release = mf_Release;
9094  message_filter.HandleInComingCall = mf_HandleInComingCall;
9095  message_filter.RetryRejectedCall = mf_RetryRejectedCall;
9096  message_filter.MessagePending = mf_MessagePending;
9097 
9100 
9101  cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
9102 
9104 
9105  rb_define_method(cWIN32OLE, "initialize", fole_initialize, -1);
9106 
9109 
9111  rb_define_singleton_method(cWIN32OLE, "ole_reference_count", fole_s_reference_count, 1);
9112  rb_define_singleton_method(cWIN32OLE, "ole_show_help", fole_s_show_help, -1);
9120 
9121  rb_define_method(cWIN32OLE, "invoke", fole_invoke, -1);
9123  rb_define_method(cWIN32OLE, "_invoke", fole_invoke2, 3);
9124  rb_define_method(cWIN32OLE, "_getproperty", fole_getproperty2, 3);
9125  rb_define_method(cWIN32OLE, "_setproperty", fole_setproperty2, 3);
9126 
9127  /* support propput method that takes an argument */
9129 
9130  rb_define_method(cWIN32OLE, "ole_free", fole_free, 0);
9131 
9132  rb_define_method(cWIN32OLE, "each", fole_each, 0);
9133  rb_define_method(cWIN32OLE, "method_missing", fole_missing, -1);
9134 
9135  /* support setproperty method much like Perl ;-) */
9136  rb_define_method(cWIN32OLE, "setproperty", fole_setproperty, -1);
9137 
9138  rb_define_method(cWIN32OLE, "ole_methods", fole_methods, 0);
9139  rb_define_method(cWIN32OLE, "ole_get_methods", fole_get_methods, 0);
9140  rb_define_method(cWIN32OLE, "ole_put_methods", fole_put_methods, 0);
9141  rb_define_method(cWIN32OLE, "ole_func_methods", fole_func_methods, 0);
9142 
9143  rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1);
9144  rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method");
9145  rb_define_method(cWIN32OLE, "ole_activex_initialize", fole_activex_initialize, 0);
9146  rb_define_method(cWIN32OLE, "ole_type", fole_type, 0);
9147  rb_define_alias(cWIN32OLE, "ole_obj_help", "ole_type");
9148  rb_define_method(cWIN32OLE, "ole_typelib", fole_typelib, 0);
9149  rb_define_method(cWIN32OLE, "ole_query_interface", fole_query_interface, 1);
9150  rb_define_method(cWIN32OLE, "ole_respond_to?", fole_respond_to, 1);
9151 
9153  rb_define_const(cWIN32OLE, "ARGV", rb_ary_new());
9154 
9155  rb_define_const(cWIN32OLE, "CP_ACP", INT2FIX(CP_ACP));
9156  rb_define_const(cWIN32OLE, "CP_OEMCP", INT2FIX(CP_OEMCP));
9157  rb_define_const(cWIN32OLE, "CP_MACCP", INT2FIX(CP_MACCP));
9158  rb_define_const(cWIN32OLE, "CP_THREAD_ACP", INT2FIX(CP_THREAD_ACP));
9159  rb_define_const(cWIN32OLE, "CP_SYMBOL", INT2FIX(CP_SYMBOL));
9160  rb_define_const(cWIN32OLE, "CP_UTF7", INT2FIX(CP_UTF7));
9161  rb_define_const(cWIN32OLE, "CP_UTF8", INT2FIX(CP_UTF8));
9162 
9163  rb_define_const(cWIN32OLE, "LOCALE_SYSTEM_DEFAULT", INT2FIX(LOCALE_SYSTEM_DEFAULT));
9164  rb_define_const(cWIN32OLE, "LOCALE_USER_DEFAULT", INT2FIX(LOCALE_USER_DEFAULT));
9165 
9167  rb_define_const(mWIN32OLE_VARIANT, "VT_EMPTY", INT2FIX(VT_EMPTY));
9168  rb_define_const(mWIN32OLE_VARIANT, "VT_NULL", INT2FIX(VT_NULL));
9169  rb_define_const(mWIN32OLE_VARIANT, "VT_I2", INT2FIX(VT_I2));
9170  rb_define_const(mWIN32OLE_VARIANT, "VT_I4", INT2FIX(VT_I4));
9171  rb_define_const(mWIN32OLE_VARIANT, "VT_R4", INT2FIX(VT_R4));
9172  rb_define_const(mWIN32OLE_VARIANT, "VT_R8", INT2FIX(VT_R8));
9173  rb_define_const(mWIN32OLE_VARIANT, "VT_CY", INT2FIX(VT_CY));
9174  rb_define_const(mWIN32OLE_VARIANT, "VT_DATE", INT2FIX(VT_DATE));
9175  rb_define_const(mWIN32OLE_VARIANT, "VT_BSTR", INT2FIX(VT_BSTR));
9176  rb_define_const(mWIN32OLE_VARIANT, "VT_USERDEFINED", INT2FIX(VT_USERDEFINED));
9177  rb_define_const(mWIN32OLE_VARIANT, "VT_PTR", INT2FIX(VT_PTR));
9178  rb_define_const(mWIN32OLE_VARIANT, "VT_DISPATCH", INT2FIX(VT_DISPATCH));
9179  rb_define_const(mWIN32OLE_VARIANT, "VT_ERROR", INT2FIX(VT_ERROR));
9180  rb_define_const(mWIN32OLE_VARIANT, "VT_BOOL", INT2FIX(VT_BOOL));
9181  rb_define_const(mWIN32OLE_VARIANT, "VT_VARIANT", INT2FIX(VT_VARIANT));
9182  rb_define_const(mWIN32OLE_VARIANT, "VT_UNKNOWN", INT2FIX(VT_UNKNOWN));
9183  rb_define_const(mWIN32OLE_VARIANT, "VT_I1", INT2FIX(VT_I1));
9184  rb_define_const(mWIN32OLE_VARIANT, "VT_UI1", INT2FIX(VT_UI1));
9185  rb_define_const(mWIN32OLE_VARIANT, "VT_UI2", INT2FIX(VT_UI2));
9186  rb_define_const(mWIN32OLE_VARIANT, "VT_UI4", INT2FIX(VT_UI4));
9187 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
9188  rb_define_const(mWIN32OLE_VARIANT, "VT_I8", INT2FIX(VT_I8));
9189  rb_define_const(mWIN32OLE_VARIANT, "VT_UI8", INT2FIX(VT_UI8));
9190 #endif
9191  rb_define_const(mWIN32OLE_VARIANT, "VT_INT", INT2FIX(VT_INT));
9192  rb_define_const(mWIN32OLE_VARIANT, "VT_UINT", INT2FIX(VT_UINT));
9193  rb_define_const(mWIN32OLE_VARIANT, "VT_ARRAY", INT2FIX(VT_ARRAY));
9194  rb_define_const(mWIN32OLE_VARIANT, "VT_BYREF", INT2FIX(VT_BYREF));
9195 
9196  cWIN32OLE_TYPELIB = rb_define_class("WIN32OLE_TYPELIB", rb_cObject);
9207  rb_define_alias(cWIN32OLE_TYPELIB, "ole_classes", "ole_types");
9210  rb_define_alias(cWIN32OLE_TYPELIB, "to_s", "name");
9212 
9213  cWIN32OLE_TYPE = rb_define_class("WIN32OLE_TYPE", rb_cObject);
9224  rb_define_alias(cWIN32OLE_TYPE, "to_s", "name");
9233  rb_define_method(cWIN32OLE_TYPE, "ole_methods", foletype_methods, 0);
9235  rb_define_method(cWIN32OLE_TYPE, "implemented_ole_types", foletype_impl_ole_types, 0);
9237  rb_define_method(cWIN32OLE_TYPE, "default_event_sources", foletype_default_event_sources, 0);
9240 
9241  cWIN32OLE_VARIABLE = rb_define_class("WIN32OLE_VARIABLE", rb_cObject);
9250  rb_define_alias(cWIN32OLE_VARIABLE, "to_s", "name");
9251 
9252  cWIN32OLE_METHOD = rb_define_class("WIN32OLE_METHOD", rb_cObject);
9272  rb_define_alias(cWIN32OLE_METHOD, "to_s", "name");
9274 
9275  cWIN32OLE_PARAM = rb_define_class("WIN32OLE_PARAM", rb_cObject);
9286  rb_define_alias(cWIN32OLE_PARAM, "to_s", "name");
9288 
9289  cWIN32OLE_EVENT = rb_define_class("WIN32OLE_EVENT", rb_cObject);
9292  rb_define_method(cWIN32OLE_EVENT, "initialize", fev_initialize, -1);
9293  rb_define_method(cWIN32OLE_EVENT, "on_event", fev_on_event, -1);
9294  rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1);
9295  rb_define_method(cWIN32OLE_EVENT, "off_event", fev_off_event, -1);
9299 
9300  cWIN32OLE_VARIANT = rb_define_class("WIN32OLE_VARIANT", rb_cObject);
9311  rb_define_const(cWIN32OLE_VARIANT, "Nothing", rb_funcall(cWIN32OLE_VARIANT, rb_intern("new"), 2, Qnil, INT2FIX(VT_DISPATCH)));
9312 
9313  eWIN32OLERuntimeError = rb_define_class("WIN32OLERuntimeError", rb_eRuntimeError);
9314 
9315  init_enc2cp();
9316  atexit((void (*)(void))free_enc2cp);
9317  ole_init_cp();
9318 }
9319