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