Ruby  2.0.0p481(2014-05-08revision45883)
ext/win32ole/win32ole.c
Go to the documentation of this file.
00001 /*
00002  *  (c) 1995 Microsoft Corporation. All rights reserved.
00003  *  Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
00004  *
00005  *  Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy
00006  *  <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net>
00007  *
00008  *  You may distribute under the terms of either the GNU General Public
00009  *  License or the Artistic License, as specified in the README file
00010  *  of the Perl distribution.
00011  *
00012  */
00013 
00014 /*
00015   modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp>
00016  */
00017 
00018 #include "ruby/ruby.h"
00019 #include "ruby/st.h"
00020 #include "ruby/encoding.h"
00021 
00022 #define GNUC_OLDER_3_4_4 \
00023     ((__GNUC__ < 3) || \
00024      ((__GNUC__ <= 3) && (__GNUC_MINOR__ < 4)) || \
00025      ((__GNUC__ <= 3) && (__GNUC_MINOR__ <= 4) && (__GNUC_PATCHLEVEL__ <= 4)))
00026 
00027 #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
00028 #ifndef NONAMELESSUNION
00029 #define NONAMELESSUNION 1
00030 #endif
00031 #endif
00032 
00033 #include <ctype.h>
00034 
00035 #include <windows.h>
00036 #include <ocidl.h>
00037 #include <olectl.h>
00038 #include <ole2.h>
00039 #if defined(HAVE_TYPE_IMULTILANGUAGE2) || defined(HAVE_TYPE_IMULTILANGUAGE)
00040 #include <mlang.h>
00041 #endif
00042 #include <stdlib.h>
00043 #include <math.h>
00044 #ifdef HAVE_STDARG_PROTOTYPES
00045 #include <stdarg.h>
00046 #define va_init_list(a,b) va_start(a,b)
00047 #else
00048 #include <varargs.h>
00049 #define va_init_list(a,b) va_start(a)
00050 #endif
00051 #include <objidl.h>
00052 
00053 #define DOUT fprintf(stderr,"[%d]\n",__LINE__)
00054 #define DOUTS(x) fprintf(stderr,"[%d]:" #x "=%s\n",__LINE__,x)
00055 #define DOUTMSG(x) fprintf(stderr, "[%d]:" #x "\n",__LINE__)
00056 #define DOUTI(x) fprintf(stderr, "[%ld]:" #x "=%d\n",__LINE__,x)
00057 #define DOUTD(x) fprintf(stderr, "[%d]:" #x "=%f\n",__LINE__,x)
00058 
00059 #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
00060 #define V_UNION1(X, Y) ((X)->u.Y)
00061 #else
00062 #define V_UNION1(X, Y) ((X)->Y)
00063 #endif
00064 
00065 #if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
00066 #undef V_UNION
00067 #define V_UNION(X,Y) ((X)->n1.n2.n3.Y)
00068 
00069 #undef V_VT
00070 #define V_VT(X) ((X)->n1.n2.vt)
00071 
00072 #undef V_BOOL
00073 #define V_BOOL(X) V_UNION(X,boolVal)
00074 #endif
00075 
00076 #ifndef V_I1REF
00077 #define V_I1REF(X) V_UNION(X, pcVal)
00078 #endif
00079 
00080 #ifndef V_UI2REF
00081 #define V_UI2REF(X) V_UNION(X, puiVal)
00082 #endif
00083 
00084 #ifndef V_INT
00085 #define V_INT(X) V_UNION(X, intVal)
00086 #endif
00087 
00088 #ifndef V_INTREF
00089 #define V_INTREF(X) V_UNION(X, pintVal)
00090 #endif
00091 
00092 #ifndef V_UINT
00093 #define V_UINT(X) V_UNION(X, uintVal)
00094 #endif
00095 
00096 #ifndef V_UINTREF
00097 #define V_UINTREF(X) V_UNION(X, puintVal)
00098 #endif
00099 
00100 /*
00101  * unfortunately IID_IMultiLanguage2 is not included in any libXXX.a
00102  * in Cygwin(mingw32).
00103  */
00104 #if defined(__CYGWIN__) ||  defined(__MINGW32__)
00105 #undef IID_IMultiLanguage2
00106 const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}};
00107 #endif
00108 
00109 #define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0
00110 
00111 #define OLE_ADDREF(X) (X) ? ((X)->lpVtbl->AddRef(X)) : 0
00112 
00113 #define OLE_GET_TYPEATTR(X, Y) ((X)->lpVtbl->GetTypeAttr((X), (Y)))
00114 #define OLE_RELEASE_TYPEATTR(X, Y) ((X)->lpVtbl->ReleaseTypeAttr((X), (Y)))
00115 
00116 #define OLE_FREE(x) {\
00117     if(g_ole_initialized == TRUE) {\
00118         if(x) {\
00119             OLE_RELEASE(x);\
00120             (x) = 0;\
00121         }\
00122     }\
00123 }
00124 
00125 #define OLEData_Get_Struct(obj, pole) {\
00126     Data_Get_Struct(obj, struct oledata, pole);\
00127     if(!pole->pDispatch) {\
00128         rb_raise(rb_eRuntimeError, "failed to get Dispatch Interface");\
00129     }\
00130 }
00131 
00132 #ifdef HAVE_LONG_LONG
00133 #define I8_2_NUM LL2NUM
00134 #define UI8_2_NUM ULL2NUM
00135 #define NUM2I8  NUM2LL
00136 #define NUM2UI8 NUM2ULL
00137 #else
00138 #define I8_2_NUM INT2NUM
00139 #define UI8_2_NUM UINT2NUM
00140 #define NUM2I8  NUM2INT
00141 #define NUM2UI8 NUM2UINT
00142 #endif
00143 
00144 #define WC2VSTR(x) ole_wc2vstr((x), TRUE)
00145 
00146 #define WIN32OLE_VERSION "1.5.4"
00147 
00148 typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
00149     (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
00150 
00151 typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile,
00152                                  UINT uCommand, DWORD dwData);
00153 typedef BOOL (FNENUMSYSEMCODEPAGES) (CODEPAGE_ENUMPROC, DWORD);
00154 typedef struct {
00155     struct IEventSinkVtbl * lpVtbl;
00156 } IEventSink, *PEVENTSINK;
00157 
00158 typedef struct IEventSinkVtbl IEventSinkVtbl;
00159 
00160 struct IEventSinkVtbl {
00161     STDMETHOD(QueryInterface)(
00162         PEVENTSINK,
00163         REFIID,
00164         LPVOID *);
00165     STDMETHOD_(ULONG, AddRef)(PEVENTSINK);
00166     STDMETHOD_(ULONG, Release)(PEVENTSINK);
00167 
00168     STDMETHOD(GetTypeInfoCount)(
00169         PEVENTSINK,
00170         UINT *);
00171     STDMETHOD(GetTypeInfo)(
00172         PEVENTSINK,
00173         UINT,
00174         LCID,
00175         ITypeInfo **);
00176     STDMETHOD(GetIDsOfNames)(
00177         PEVENTSINK,
00178         REFIID,
00179         OLECHAR **,
00180         UINT,
00181         LCID,
00182         DISPID *);
00183     STDMETHOD(Invoke)(
00184         PEVENTSINK,
00185         DISPID,
00186         REFIID,
00187         LCID,
00188         WORD,
00189         DISPPARAMS *,
00190         VARIANT *,
00191         EXCEPINFO *,
00192         UINT *);
00193 };
00194 
00195 typedef struct tagIEVENTSINKOBJ {
00196     IEventSinkVtbl *lpVtbl;
00197     DWORD m_cRef;
00198     IID m_iid;
00199     int m_event_id;
00200     ITypeInfo *pTypeInfo;
00201 }IEVENTSINKOBJ, *PIEVENTSINKOBJ;
00202 
00203 VALUE cWIN32OLE;
00204 VALUE cWIN32OLE_TYPELIB;
00205 VALUE cWIN32OLE_TYPE;
00206 VALUE cWIN32OLE_VARIABLE;
00207 VALUE cWIN32OLE_METHOD;
00208 VALUE cWIN32OLE_PARAM;
00209 VALUE cWIN32OLE_EVENT;
00210 VALUE cWIN32OLE_VARIANT;
00211 VALUE eWIN32OLERuntimeError;
00212 VALUE mWIN32OLE_VARIANT;
00213 VALUE cWIN32OLE_PROPERTY;
00214 
00215 static VALUE ary_ole_event;
00216 static ID id_events;
00217 #if defined(RB_THREAD_SPECIFIC) && (defined(__CYGWIN__) || defined(__MINGW32__))
00218 static RB_THREAD_SPECIFIC BOOL g_ole_initialized;
00219 # define g_ole_initialized_init() ((void)0)
00220 # define g_ole_initialized_set(val) (g_ole_initialized = (val))
00221 #else
00222 static volatile DWORD g_ole_initialized_key = TLS_OUT_OF_INDEXES;
00223 # define g_ole_initialized (BOOL)TlsGetValue(g_ole_initialized_key)
00224 # define g_ole_initialized_init() (g_ole_initialized_key = TlsAlloc())
00225 # define g_ole_initialized_set(val) TlsSetValue(g_ole_initialized_key, (void*)(val))
00226 #endif
00227 static BOOL g_uninitialize_hooked = FALSE;
00228 static BOOL g_cp_installed = FALSE;
00229 static BOOL g_lcid_installed = FALSE;
00230 static HINSTANCE ghhctrl = NULL;
00231 static HINSTANCE gole32 = NULL;
00232 static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL;
00233 static VALUE com_hash;
00234 static IDispatchVtbl com_vtbl;
00235 static UINT cWIN32OLE_cp = CP_ACP;
00236 static LCID cWIN32OLE_lcid = LOCALE_SYSTEM_DEFAULT;
00237 static rb_encoding *cWIN32OLE_enc;
00238 static UINT g_cp_to_check = CP_ACP;
00239 static char g_lcid_to_check[8 + 1];
00240 static VARTYPE g_nil_to = VT_ERROR;
00241 static st_table *enc2cp_table;
00242 static IMessageFilterVtbl message_filter;
00243 static IMessageFilter imessage_filter = { &message_filter };
00244 static IMessageFilter* previous_filter;
00245 
00246 #if defined(HAVE_TYPE_IMULTILANGUAGE2)
00247 static IMultiLanguage2 *pIMultiLanguage = NULL;
00248 #elif defined(HAVE_TYPE_IMULTILANGUAGE)
00249 static IMultiLanguage *pIMultiLanguage = NULL;
00250 #else
00251 #define pIMultiLanguage NULL /* dummy */
00252 #endif
00253 
00254 struct oledata {
00255     IDispatch *pDispatch;
00256 };
00257 
00258 struct oletypelibdata {
00259     ITypeLib *pTypeLib;
00260 };
00261 
00262 struct oletypedata {
00263     ITypeInfo *pTypeInfo;
00264 };
00265 
00266 struct olemethoddata {
00267     ITypeInfo *pOwnerTypeInfo;
00268     ITypeInfo *pTypeInfo;
00269     UINT index;
00270 };
00271 
00272 struct olevariabledata {
00273     ITypeInfo *pTypeInfo;
00274     UINT index;
00275 };
00276 
00277 struct oleparamdata {
00278     ITypeInfo *pTypeInfo;
00279     UINT method_index;
00280     UINT index;
00281 };
00282 
00283 struct oleeventdata {
00284     DWORD dwCookie;
00285     IConnectionPoint *pConnectionPoint;
00286     long event_id;
00287 };
00288 
00289 struct oleparam {
00290     DISPPARAMS dp;
00291     OLECHAR** pNamedArgs;
00292 };
00293 
00294 struct olevariantdata {
00295     VARIANT realvar;
00296     VARIANT var;
00297 };
00298 
00299 
00300 static HRESULT ( STDMETHODCALLTYPE QueryInterface )(IDispatch __RPC_FAR *, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
00301 static ULONG ( STDMETHODCALLTYPE AddRef )(IDispatch __RPC_FAR * This);
00302 static ULONG ( STDMETHODCALLTYPE Release )(IDispatch __RPC_FAR * This);
00303 static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(IDispatch __RPC_FAR * This, UINT __RPC_FAR *pctinfo);
00304 static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(IDispatch __RPC_FAR * This, UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo);
00305 static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(IDispatch __RPC_FAR * This, REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId);
00306 static HRESULT ( STDMETHODCALLTYPE Invoke )( IDispatch __RPC_FAR * This, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult, EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr);
00307 static IDispatch* val2dispatch(VALUE val);
00308 static double rbtime2vtdate(VALUE tmobj);
00309 static VALUE vtdate2rbtime(double date);
00310 static rb_encoding *ole_cp2encoding(UINT cp);
00311 static UINT ole_encoding2cp(rb_encoding *enc);
00312 NORETURN(static void failed_load_conv51932(void));
00313 #ifndef pIMultiLanguage
00314 static void load_conv_function51932(void);
00315 #endif
00316 static UINT ole_init_cp(void);
00317 static char *ole_wc2mb(LPWSTR pw);
00318 static VALUE ole_hresult2msg(HRESULT hr);
00319 static void ole_freeexceptinfo(EXCEPINFO *pExInfo);
00320 static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo);
00321 static void ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...);
00322 static void ole_initialize(void);
00323 static void ole_msg_loop(void);
00324 static void ole_free(struct oledata *pole);
00325 static void oletypelib_free(struct oletypelibdata *poletypelib);
00326 static void oletype_free(struct oletypedata *poletype);
00327 static void olemethod_free(struct olemethoddata *polemethod);
00328 static void olevariable_free(struct olevariabledata *polevar);
00329 static void oleparam_free(struct oleparamdata *pole);
00330 static LPWSTR ole_vstr2wc(VALUE vstr);
00331 static LPWSTR ole_mb2wc(char *pm, int len);
00332 static VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree);
00333 static VALUE ole_ary_m_entry(VALUE val, long *pid);
00334 static void * get_ptr_of_variant(VARIANT *pvar);
00335 static VALUE is_all_index_under(long *pid, long *pub, long dim);
00336 static void ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim,  VARTYPE vt);
00337 static long dimension(VALUE val);
00338 static long ary_len_of_dim(VALUE ary, long dim);
00339 static HRESULT ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt);
00340 static void ole_val2variant(VALUE val, VARIANT *var);
00341 static void ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt);
00342 static void ole_val2ptr_variant(VALUE val, VARIANT *var);
00343 static void ole_set_byref(VARIANT *realvar, VARIANT *var,  VARTYPE vt);
00344 static void ole_val2olevariantdata(VALUE val, VARTYPE vt, struct olevariantdata *pvar);
00345 static void ole_val2variant2(VALUE val, VARIANT *var);
00346 static VALUE make_inspect(const char *class_name, VALUE detail);
00347 static VALUE default_inspect(VALUE self, const char *class_name);
00348 static VALUE ole_set_member(VALUE self, IDispatch *dispatch);
00349 static VALUE fole_s_allocate(VALUE klass);
00350 static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv);
00351 static VALUE ary_new_dim(VALUE myary, long *pid, long *plb, long dim);
00352 static void ary_store_dim(VALUE myary, long *pid, long *plb, long dim, VALUE val);
00353 static VALUE ole_variant2val(VARIANT *pvar);
00354 static LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey);
00355 static LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey);
00356 static VALUE reg_enum_key(HKEY hkey, DWORD i);
00357 static VALUE reg_get_val(HKEY hkey, const char *subkey);
00358 static VALUE reg_get_typelib_file_path(HKEY hkey);
00359 static VALUE typelib_file_from_clsid(VALUE ole);
00360 static VALUE typelib_file_from_typelib(VALUE ole);
00361 static VALUE typelib_file(VALUE ole);
00362 static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self);
00363 static HRESULT clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid);
00364 static VALUE ole_create_dcom(int argc, VALUE *argv, VALUE self);
00365 static VALUE ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self);
00366 static VALUE fole_s_connect(int argc, VALUE *argv, VALUE self);
00367 static VALUE fole_s_const_load(int argc, VALUE *argv, VALUE self);
00368 static VALUE ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes);
00369 static ULONG reference_count(struct oledata * pole);
00370 static VALUE fole_s_reference_count(VALUE self, VALUE obj);
00371 static VALUE fole_s_free(VALUE self, VALUE obj);
00372 static HWND ole_show_help(VALUE helpfile, VALUE helpcontext);
00373 static VALUE fole_s_show_help(int argc, VALUE *argv, VALUE self);
00374 static VALUE fole_s_get_code_page(VALUE self);
00375 static BOOL CALLBACK installed_code_page_proc(LPTSTR str);
00376 static BOOL code_page_installed(UINT cp);
00377 static VALUE fole_s_set_code_page(VALUE self, VALUE vcp);
00378 static VALUE fole_s_get_locale(VALUE self);
00379 static BOOL CALLBACK installed_lcid_proc(LPTSTR str);
00380 static BOOL lcid_installed(LCID lcid);
00381 static VALUE fole_s_set_locale(VALUE self, VALUE vlcid);
00382 static VALUE fole_s_create_guid(VALUE self);
00383 static VALUE fole_s_ole_initialize(VALUE self);
00384 static VALUE fole_s_ole_uninitialize(VALUE self);
00385 static VALUE fole_initialize(int argc, VALUE *argv, VALUE self);
00386 static VALUE hash2named_arg(VALUE pair, struct oleparam* pOp);
00387 static VALUE set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end);
00388 static VALUE ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket);
00389 static VALUE fole_invoke(int argc, VALUE *argv, VALUE self);
00390 static VALUE ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind);
00391 static VALUE fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types);
00392 static VALUE fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
00393 static VALUE fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
00394 static VALUE fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self);
00395 static VALUE fole_setproperty(int argc, VALUE *argv, VALUE self);
00396 static VALUE fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self);
00397 static VALUE ole_propertyput(VALUE self, VALUE property, VALUE value);
00398 static VALUE fole_free(VALUE self);
00399 static VALUE ole_each_sub(VALUE pEnumV);
00400 static VALUE ole_ienum_free(VALUE pEnumV);
00401 static VALUE fole_each(VALUE self);
00402 static VALUE fole_missing(int argc, VALUE *argv, VALUE self);
00403 static VALUE ole_method_sub(VALUE self, ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE name);
00404 static VALUE olemethod_from_typeinfo(VALUE self, ITypeInfo *pTypeInfo, VALUE name);
00405 static VALUE ole_methods_sub(ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE methods, int mask);
00406 static VALUE ole_methods_from_typeinfo(ITypeInfo *pTypeInfo, int mask);
00407 static HRESULT typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti);
00408 static VALUE ole_methods(VALUE self, int mask);
00409 static VALUE fole_methods(VALUE self);
00410 static VALUE fole_get_methods(VALUE self);
00411 static VALUE fole_put_methods(VALUE self);
00412 static VALUE fole_func_methods(VALUE self);
00413 static VALUE ole_type_from_itypeinfo(ITypeInfo *pTypeInfo);
00414 static VALUE fole_type(VALUE self);
00415 static VALUE ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo);
00416 static VALUE fole_typelib(VALUE self);
00417 static VALUE fole_query_interface(VALUE self, VALUE str_iid);
00418 static VALUE fole_respond_to(VALUE self, VALUE method);
00419 static HRESULT ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile);
00420 static VALUE ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
00421 static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
00422 static VALUE ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
00423 static VALUE fole_method_help(VALUE self, VALUE cmdname);
00424 static VALUE fole_activex_initialize(VALUE self);
00425 static VALUE foletype_s_ole_classes(VALUE self, VALUE typelib);
00426 static VALUE foletype_s_typelibs(VALUE self);
00427 static VALUE foletype_s_progids(VALUE self);
00428 static VALUE foletype_s_allocate(VALUE klass);
00429 static VALUE oletype_set_member(VALUE self, ITypeInfo *pTypeInfo, VALUE name);
00430 static VALUE oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass);
00431 static VALUE oletypelib_set_member(VALUE self, ITypeLib *pTypeLib);
00432 static ITypeLib * oletypelib_get_typelib(VALUE self);
00433 static void oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr);
00434 static VALUE foletypelib_s_typelibs(VALUE self);
00435 static VALUE make_version_str(VALUE major, VALUE minor);
00436 static VALUE oletypelib_search_registry2(VALUE self, VALUE args);
00437 static VALUE oletypelib_search_registry(VALUE self, VALUE typelib);
00438 static VALUE foletypelib_s_allocate(VALUE klass);
00439 static VALUE foletypelib_initialize(VALUE self, VALUE args);
00440 static VALUE foletypelib_guid(VALUE self);
00441 static VALUE foletypelib_name(VALUE self);
00442 static VALUE foletypelib_version(VALUE self);
00443 static VALUE foletypelib_major_version(VALUE self);
00444 static VALUE foletypelib_minor_version(VALUE self);
00445 static VALUE oletypelib_path(VALUE guid, VALUE version);
00446 static HRESULT oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib);
00447 static VALUE foletypelib_path(VALUE self);
00448 static VALUE foletypelib_visible(VALUE self);
00449 static VALUE foletypelib_library_name(VALUE self);
00450 static VALUE foletypelib_ole_types(VALUE self);
00451 static VALUE foletypelib_inspect(VALUE self);
00452 static VALUE foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass);
00453 static VALUE foletype_name(VALUE self);
00454 static VALUE ole_ole_type(ITypeInfo *pTypeInfo);
00455 static VALUE foletype_ole_type(VALUE self);
00456 static VALUE ole_type_guid(ITypeInfo *pTypeInfo);
00457 static VALUE foletype_guid(VALUE self);
00458 static VALUE ole_type_progid(ITypeInfo *pTypeInfo);
00459 static VALUE foletype_progid(VALUE self);
00460 static VALUE ole_type_visible(ITypeInfo *pTypeInfo);
00461 static VALUE foletype_visible(VALUE self);
00462 static VALUE ole_type_major_version(ITypeInfo *pTypeInfo);
00463 static VALUE foletype_major_version(VALUE self);
00464 static VALUE ole_type_minor_version(ITypeInfo *pTypeInfo);
00465 static VALUE foletype_minor_version(VALUE self);
00466 static VALUE ole_type_typekind(ITypeInfo *pTypeInfo);
00467 static VALUE foletype_typekind(VALUE self);
00468 static VALUE ole_type_helpstring(ITypeInfo *pTypeInfo);
00469 static VALUE foletype_helpstring(VALUE self);
00470 static VALUE ole_type_src_type(ITypeInfo *pTypeInfo);
00471 static VALUE foletype_src_type(VALUE self);
00472 static VALUE ole_type_helpfile(ITypeInfo *pTypeInfo);
00473 static VALUE foletype_helpfile(VALUE self);
00474 static VALUE ole_type_helpcontext(ITypeInfo *pTypeInfo);
00475 static VALUE foletype_helpcontext(VALUE self);
00476 static VALUE foletype_ole_typelib(VALUE self);
00477 static VALUE ole_type_impl_ole_types(ITypeInfo *pTypeInfo, int implflags);
00478 static VALUE foletype_impl_ole_types(VALUE self);
00479 static VALUE foletype_source_ole_types(VALUE self);
00480 static VALUE foletype_default_event_sources(VALUE self);
00481 static VALUE foletype_default_ole_types(VALUE self);
00482 static VALUE foletype_inspect(VALUE self);
00483 static VALUE ole_variables(ITypeInfo *pTypeInfo);
00484 static VALUE foletype_variables(VALUE self);
00485 static VALUE foletype_methods(VALUE self);
00486 static VALUE folevariable_name(VALUE self);
00487 static VALUE ole_variable_ole_type(ITypeInfo *pTypeInfo, UINT var_index);
00488 static VALUE folevariable_ole_type(VALUE self);
00489 static VALUE ole_variable_ole_type_detail(ITypeInfo *pTypeInfo, UINT var_index);
00490 static VALUE folevariable_ole_type_detail(VALUE self);
00491 static VALUE ole_variable_value(ITypeInfo *pTypeInfo, UINT var_index);
00492 static VALUE folevariable_value(VALUE self);
00493 static VALUE ole_variable_visible(ITypeInfo *pTypeInfo, UINT var_index);
00494 static VALUE folevariable_visible(VALUE self);
00495 static VALUE ole_variable_kind(ITypeInfo *pTypeInfo, UINT var_index);
00496 static VALUE folevariable_variable_kind(VALUE self);
00497 static VALUE ole_variable_varkind(ITypeInfo *pTypeInfo, UINT var_index);
00498 static VALUE folevariable_varkind(VALUE self);
00499 static VALUE folevariable_inspect(VALUE self);
00500 static VALUE olemethod_set_member(VALUE self, ITypeInfo *pTypeInfo, ITypeInfo *pOwnerTypeInfo, int index, VALUE name);
00501 static VALUE folemethod_s_allocate(VALUE klass);
00502 static VALUE folemethod_initialize(VALUE self, VALUE oletype, VALUE method);
00503 static VALUE folemethod_name(VALUE self);
00504 static VALUE ole_method_return_type(ITypeInfo *pTypeInfo, UINT method_index);
00505 static VALUE folemethod_return_type(VALUE self);
00506 static VALUE ole_method_return_vtype(ITypeInfo *pTypeInfo, UINT method_index);
00507 static VALUE folemethod_return_vtype(VALUE self);
00508 static VALUE ole_method_return_type_detail(ITypeInfo *pTypeInfo, UINT method_index);
00509 static VALUE folemethod_return_type_detail(VALUE self);
00510 static VALUE ole_method_invkind(ITypeInfo *pTypeInfo, UINT method_index);
00511 static VALUE ole_method_invoke_kind(ITypeInfo *pTypeInfo, UINT method_index);
00512 static VALUE folemethod_invkind(VALUE self);
00513 static VALUE folemethod_invoke_kind(VALUE self);
00514 static VALUE ole_method_visible(ITypeInfo *pTypeInfo, UINT method_index);
00515 static VALUE folemethod_visible(VALUE self);
00516 static VALUE ole_method_event(ITypeInfo *pTypeInfo, UINT method_index, VALUE method_name);
00517 static VALUE folemethod_event(VALUE self);
00518 static VALUE folemethod_event_interface(VALUE self);
00519 static VALUE ole_method_docinfo_from_type(ITypeInfo *pTypeInfo, UINT method_index, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile);
00520 static VALUE ole_method_helpstring(ITypeInfo *pTypeInfo, UINT method_index);
00521 static VALUE folemethod_helpstring(VALUE self);
00522 static VALUE ole_method_helpfile(ITypeInfo *pTypeInfo, UINT method_index);
00523 static VALUE folemethod_helpfile(VALUE self);
00524 static VALUE ole_method_helpcontext(ITypeInfo *pTypeInfo, UINT method_index);
00525 static VALUE folemethod_helpcontext(VALUE self);
00526 static VALUE ole_method_dispid(ITypeInfo *pTypeInfo, UINT method_index);
00527 static VALUE folemethod_dispid(VALUE self);
00528 static VALUE ole_method_offset_vtbl(ITypeInfo *pTypeInfo, UINT method_index);
00529 static VALUE folemethod_offset_vtbl(VALUE self);
00530 static VALUE ole_method_size_params(ITypeInfo *pTypeInfo, UINT method_index);
00531 static VALUE folemethod_size_params(VALUE self);
00532 static VALUE ole_method_size_opt_params(ITypeInfo *pTypeInfo, UINT method_index);
00533 static VALUE folemethod_size_opt_params(VALUE self);
00534 static VALUE ole_method_params(ITypeInfo *pTypeInfo, UINT method_index);
00535 static VALUE folemethod_params(VALUE self);
00536 static VALUE folemethod_inspect(VALUE self);
00537 static VALUE foleparam_s_allocate(VALUE klass);
00538 static VALUE oleparam_ole_param_from_index(VALUE self, ITypeInfo *pTypeInfo, UINT method_index, int param_index);
00539 static VALUE oleparam_ole_param(VALUE self, VALUE olemethod, int n);
00540 static VALUE foleparam_initialize(VALUE self, VALUE olemethod, VALUE n);
00541 static VALUE foleparam_name(VALUE self);
00542 static VALUE ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index);
00543 static VALUE foleparam_ole_type(VALUE self);
00544 static VALUE ole_param_ole_type_detail(ITypeInfo *pTypeInfo, UINT method_index, UINT index);
00545 static VALUE foleparam_ole_type_detail(VALUE self);
00546 static VALUE ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT mask);
00547 static VALUE foleparam_input(VALUE self);
00548 static VALUE foleparam_output(VALUE self);
00549 static VALUE foleparam_optional(VALUE self);
00550 static VALUE foleparam_retval(VALUE self);
00551 static VALUE ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index);
00552 static VALUE foleparam_default(VALUE self);
00553 static VALUE foleparam_inspect(VALUE self);
00554 static long ole_search_event_at(VALUE ary, VALUE ev);
00555 static VALUE ole_search_event(VALUE ary, VALUE ev, BOOL  *is_default);
00556 static VALUE ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler);
00557 static void ole_delete_event(VALUE ary, VALUE ev);
00558 static void hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams);
00559 static VALUE hash2result(VALUE hash);
00560 static void ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams);
00561 static VALUE exec_callback(VALUE arg);
00562 static VALUE rescue_callback(VALUE arg);
00563 static HRESULT find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo);
00564 static HRESULT find_coclass(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **pTypeInfo2, TYPEATTR **pTypeAttr2);
00565 static HRESULT find_default_source_from_typeinfo(ITypeInfo *pTypeInfo, TYPEATTR *pTypeAttr, ITypeInfo **ppTypeInfo);
00566 static HRESULT find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo);
00567 static void ole_event_free(struct oleeventdata *poleev);
00568 static VALUE fev_s_allocate(VALUE klass);
00569 static VALUE ev_advise(int argc, VALUE *argv, VALUE self);
00570 static VALUE fev_initialize(int argc, VALUE *argv, VALUE self);
00571 static VALUE fev_s_msg_loop(VALUE klass);
00572 static void add_event_call_back(VALUE obj, VALUE event, VALUE data);
00573 static VALUE ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg);
00574 static VALUE fev_on_event(int argc, VALUE *argv, VALUE self);
00575 static VALUE fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self);
00576 static VALUE fev_off_event(int argc, VALUE *argv, VALUE self);
00577 static VALUE fev_unadvise(VALUE self);
00578 static VALUE fev_set_handler(VALUE self, VALUE val);
00579 static VALUE fev_get_handler(VALUE self);
00580 static VALUE evs_push(VALUE ev);
00581 static VALUE evs_delete(long i);
00582 static VALUE evs_entry(long i);
00583 static VALUE evs_length(void);
00584 static void  olevariant_free(struct olevariantdata *pvar);
00585 static VALUE folevariant_s_allocate(VALUE klass);
00586 static VALUE folevariant_s_array(VALUE klass, VALUE dims, VALUE vvt);
00587 static VALUE folevariant_initialize(VALUE self, VALUE args);
00588 static long *ary2safe_array_index(int ary_size, VALUE *ary, SAFEARRAY *psa);
00589 static void unlock_safe_array(SAFEARRAY *psa);
00590 static SAFEARRAY *get_locked_safe_array(VALUE val);
00591 static VALUE folevariant_ary_aref(int argc, VALUE *argv, VALUE self);
00592 static VOID * val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt);
00593 static VALUE folevariant_ary_aset(int argc, VALUE *argv, VALUE self);
00594 static VALUE folevariant_value(VALUE self);
00595 static VALUE folevariant_vartype(VALUE self);
00596 static VALUE folevariant_set_value(VALUE self, VALUE val);
00597 static void init_enc2cp(void);
00598 static void free_enc2cp(void);
00599 
00600 static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)(
00601     IMessageFilter __RPC_FAR * This,
00602     /* [in] */ REFIID riid,
00603     /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
00604 {
00605     if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
00606         || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0)
00607     {
00608         *ppvObject = &message_filter;
00609         return S_OK;
00610     }
00611     return E_NOINTERFACE;
00612 }
00613 
00614 static ULONG (STDMETHODCALLTYPE mf_AddRef)(
00615     IMessageFilter __RPC_FAR * This)
00616 {
00617     return 1;
00618 }
00619 
00620 static ULONG (STDMETHODCALLTYPE mf_Release)(
00621     IMessageFilter __RPC_FAR * This)
00622 {
00623     return 1;
00624 }
00625 
00626 static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)(
00627     IMessageFilter __RPC_FAR * pThis,
00628     DWORD dwCallType,      //Type of incoming call
00629     HTASK threadIDCaller,  //Task handle calling this task
00630     DWORD dwTickCount,     //Elapsed tick count
00631     LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure
00632     )
00633 {
00634 #ifdef DEBUG_MESSAGEFILTER
00635     printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount);
00636     fflush(stdout);
00637 #endif
00638     switch (dwCallType)
00639     {
00640     case CALLTYPE_ASYNC:
00641     case CALLTYPE_TOPLEVEL_CALLPENDING:
00642     case CALLTYPE_ASYNC_CALLPENDING:
00643         if (rb_during_gc()) {
00644             return SERVERCALL_RETRYLATER;
00645         }
00646         break;
00647     default:
00648         break;
00649     }
00650     if (previous_filter) {
00651         return previous_filter->lpVtbl->HandleInComingCall(previous_filter,
00652                                                    dwCallType,
00653                                                    threadIDCaller,
00654                                                    dwTickCount,
00655                                                    lpInterfaceInfo);
00656     }
00657     return SERVERCALL_ISHANDLED;
00658 }
00659 
00660 static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)(
00661     IMessageFilter* pThis,
00662     HTASK threadIDCallee,  //Server task handle
00663     DWORD dwTickCount,     //Elapsed tick count
00664     DWORD dwRejectType     //Returned rejection message
00665     )
00666 {
00667     if (previous_filter) {
00668         return previous_filter->lpVtbl->RetryRejectedCall(previous_filter,
00669                                                   threadIDCallee,
00670                                                   dwTickCount,
00671                                                   dwRejectType);
00672     }
00673     return 1000;
00674 }
00675 
00676 static DWORD (STDMETHODCALLTYPE mf_MessagePending)(
00677     IMessageFilter* pThis,
00678     HTASK threadIDCallee,  //Called applications task handle
00679     DWORD dwTickCount,     //Elapsed tick count
00680     DWORD dwPendingType    //Call type
00681     )
00682 {
00683     if (rb_during_gc()) {
00684         return PENDINGMSG_WAITNOPROCESS;
00685     }
00686     if (previous_filter) {
00687         return previous_filter->lpVtbl->MessagePending(previous_filter,
00688                                                threadIDCallee,
00689                                                dwTickCount,
00690                                                dwPendingType);
00691     }
00692     return PENDINGMSG_WAITNOPROCESS;
00693 }
00694 
00695 typedef struct _Win32OLEIDispatch
00696 {
00697     IDispatch dispatch;
00698     ULONG refcount;
00699     VALUE obj;
00700 } Win32OLEIDispatch;
00701 
00702 static HRESULT ( STDMETHODCALLTYPE QueryInterface )(
00703     IDispatch __RPC_FAR * This,
00704     /* [in] */ REFIID riid,
00705     /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
00706 {
00707     if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
00708         || MEMCMP(riid, &IID_IDispatch, GUID, 1) == 0)
00709     {
00710         Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
00711         p->refcount++;
00712         *ppvObject = This;
00713         return S_OK;
00714     }
00715     return E_NOINTERFACE;
00716 }
00717 
00718 static ULONG ( STDMETHODCALLTYPE AddRef )(
00719     IDispatch __RPC_FAR * This)
00720 {
00721     Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
00722     return ++(p->refcount);
00723 }
00724 
00725 static ULONG ( STDMETHODCALLTYPE Release )(
00726     IDispatch __RPC_FAR * This)
00727 {
00728     Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
00729     ULONG u = --(p->refcount);
00730     if (u == 0) {
00731         st_data_t key = p->obj;
00732         st_delete(DATA_PTR(com_hash), &key, 0);
00733         free(p);
00734     }
00735     return u;
00736 }
00737 
00738 static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(
00739     IDispatch __RPC_FAR * This,
00740     /* [out] */ UINT __RPC_FAR *pctinfo)
00741 {
00742     return E_NOTIMPL;
00743 }
00744 
00745 static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(
00746     IDispatch __RPC_FAR * This,
00747     /* [in] */ UINT iTInfo,
00748     /* [in] */ LCID lcid,
00749     /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
00750 {
00751     return E_NOTIMPL;
00752 }
00753 
00754 
00755 static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(
00756     IDispatch __RPC_FAR * This,
00757     /* [in] */ REFIID riid,
00758     /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
00759     /* [in] */ UINT cNames,
00760     /* [in] */ LCID lcid,
00761     /* [size_is][out] */ DISPID __RPC_FAR *rgDispId)
00762 {
00763     /*
00764     Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
00765     */
00766     char* psz = ole_wc2mb(*rgszNames); // support only one method
00767     *rgDispId = rb_intern(psz);
00768     free(psz);
00769     return S_OK;
00770 }
00771 
00772 static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )(
00773     IDispatch __RPC_FAR * This,
00774     /* [in] */ DISPID dispIdMember,
00775     /* [in] */ REFIID riid,
00776     /* [in] */ LCID lcid,
00777     /* [in] */ WORD wFlags,
00778     /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
00779     /* [out] */ VARIANT __RPC_FAR *pVarResult,
00780     /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
00781     /* [out] */ UINT __RPC_FAR *puArgErr)
00782 {
00783     VALUE v;
00784     int i;
00785     int args = pDispParams->cArgs;
00786     Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
00787     VALUE* parg = ALLOCA_N(VALUE, args);
00788     for (i = 0; i < args; i++) {
00789         *(parg + i) = ole_variant2val(&pDispParams->rgvarg[args - i - 1]);
00790     }
00791     if (dispIdMember == DISPID_VALUE) {
00792         if (wFlags == DISPATCH_METHOD) {
00793             dispIdMember = rb_intern("call");
00794         } else if (wFlags & DISPATCH_PROPERTYGET) {
00795             dispIdMember = rb_intern("value");
00796         }
00797     }
00798     v = rb_funcall2(p->obj, dispIdMember, args, parg);
00799     ole_val2variant(v, pVarResult);
00800     return S_OK;
00801 }
00802 
00803 static IDispatch*
00804 val2dispatch(VALUE val)
00805 {
00806     struct st_table *tbl = DATA_PTR(com_hash);
00807     Win32OLEIDispatch* pdisp;
00808     st_data_t data;
00809 
00810     if (st_lookup(tbl, val, &data)) {
00811         pdisp = (Win32OLEIDispatch *)(data & ~FIXNUM_FLAG);
00812         pdisp->refcount++;
00813     }
00814     else {
00815         pdisp = ALLOC(Win32OLEIDispatch);
00816         pdisp->dispatch.lpVtbl = &com_vtbl;
00817         pdisp->refcount = 1;
00818         pdisp->obj = val;
00819         st_insert(tbl, val, (VALUE)pdisp | FIXNUM_FLAG);
00820     }
00821     return &pdisp->dispatch;
00822 }
00823 
00824 static double
00825 rbtime2vtdate(VALUE tmobj)
00826 {
00827     SYSTEMTIME st;
00828     double t = 0;
00829     memset(&st, 0, sizeof(SYSTEMTIME));
00830     st.wYear = FIX2INT(rb_funcall(tmobj, rb_intern("year"), 0));
00831     st.wMonth = FIX2INT(rb_funcall(tmobj, rb_intern("month"), 0));
00832     st.wDay = FIX2INT(rb_funcall(tmobj, rb_intern("mday"), 0));
00833     st.wHour = FIX2INT(rb_funcall(tmobj, rb_intern("hour"), 0));
00834     st.wMinute = FIX2INT(rb_funcall(tmobj, rb_intern("min"), 0));
00835     st.wSecond = FIX2INT(rb_funcall(tmobj, rb_intern("sec"), 0));
00836     st.wMilliseconds = FIX2INT(rb_funcall(tmobj, rb_intern("nsec"), 0)) / 1000000;
00837     SystemTimeToVariantTime(&st, &t);
00838     return t;
00839 }
00840 
00841 static VALUE
00842 vtdate2rbtime(double date)
00843 {
00844     SYSTEMTIME st;
00845     VALUE v;
00846     VariantTimeToSystemTime(date, &st);
00847 
00848     v = rb_funcall(rb_cTime, rb_intern("new"), 6,
00849                       INT2FIX(st.wYear),
00850                       INT2FIX(st.wMonth),
00851                       INT2FIX(st.wDay),
00852                       INT2FIX(st.wHour),
00853                       INT2FIX(st.wMinute),
00854                       INT2FIX(st.wSecond));
00855     if (st.wMilliseconds > 0) {
00856         return rb_funcall(v, rb_intern("+"), 1, rb_float_new((double)(st.wMilliseconds / 1000.0)));
00857     }
00858     return v;
00859 }
00860 
00861 #define ENC_MACHING_CP(enc,encname,cp) if(strcasecmp(rb_enc_name((enc)),(encname)) == 0) return cp
00862 
00863 static UINT ole_encoding2cp(rb_encoding *enc)
00864 {
00865     /*
00866      * Is there any better solution to convert
00867      * Ruby encoding to Windows codepage???
00868      */
00869     ENC_MACHING_CP(enc, "Big5", 950);
00870     ENC_MACHING_CP(enc, "CP51932", 51932);
00871     ENC_MACHING_CP(enc, "CP850", 850);
00872     ENC_MACHING_CP(enc, "CP852", 852);
00873     ENC_MACHING_CP(enc, "CP855", 855);
00874     ENC_MACHING_CP(enc, "CP949", 949);
00875     ENC_MACHING_CP(enc, "EUC-JP", 20932);
00876     ENC_MACHING_CP(enc, "EUC-KR", 51949);
00877     ENC_MACHING_CP(enc, "EUC-TW", 51950);
00878     ENC_MACHING_CP(enc, "GB18030", 54936);
00879     ENC_MACHING_CP(enc, "GB2312", 20936);
00880     ENC_MACHING_CP(enc, "GBK", 936);
00881     ENC_MACHING_CP(enc, "IBM437", 437);
00882     ENC_MACHING_CP(enc, "IBM737", 737);
00883     ENC_MACHING_CP(enc, "IBM775", 775);
00884     ENC_MACHING_CP(enc, "IBM852", 852);
00885     ENC_MACHING_CP(enc, "IBM855", 855);
00886     ENC_MACHING_CP(enc, "IBM857", 857);
00887     ENC_MACHING_CP(enc, "IBM860", 860);
00888     ENC_MACHING_CP(enc, "IBM861", 861);
00889     ENC_MACHING_CP(enc, "IBM862", 862);
00890     ENC_MACHING_CP(enc, "IBM863", 863);
00891     ENC_MACHING_CP(enc, "IBM864", 864);
00892     ENC_MACHING_CP(enc, "IBM865", 865);
00893     ENC_MACHING_CP(enc, "IBM866", 866);
00894     ENC_MACHING_CP(enc, "IBM869", 869);
00895     ENC_MACHING_CP(enc, "ISO-2022-JP", 50220);
00896     ENC_MACHING_CP(enc, "ISO-8859-1", 28591);
00897     ENC_MACHING_CP(enc, "ISO-8859-15", 28605);
00898     ENC_MACHING_CP(enc, "ISO-8859-2", 28592);
00899     ENC_MACHING_CP(enc, "ISO-8859-3", 28593);
00900     ENC_MACHING_CP(enc, "ISO-8859-4", 28594);
00901     ENC_MACHING_CP(enc, "ISO-8859-5", 28595);
00902     ENC_MACHING_CP(enc, "ISO-8859-6", 28596);
00903     ENC_MACHING_CP(enc, "ISO-8859-7", 28597);
00904     ENC_MACHING_CP(enc, "ISO-8859-8", 28598);
00905     ENC_MACHING_CP(enc, "ISO-8859-9", 28599);
00906     ENC_MACHING_CP(enc, "KOI8-R", 20866);
00907     ENC_MACHING_CP(enc, "KOI8-U", 21866);
00908     ENC_MACHING_CP(enc, "Shift_JIS", 932);
00909     ENC_MACHING_CP(enc, "UTF-16BE", 1201);
00910     ENC_MACHING_CP(enc, "UTF-16LE", 1200);
00911     ENC_MACHING_CP(enc, "UTF-7", 65000);
00912     ENC_MACHING_CP(enc, "UTF-8", 65001);
00913     ENC_MACHING_CP(enc, "Windows-1250", 1250);
00914     ENC_MACHING_CP(enc, "Windows-1251", 1251);
00915     ENC_MACHING_CP(enc, "Windows-1252", 1252);
00916     ENC_MACHING_CP(enc, "Windows-1253", 1253);
00917     ENC_MACHING_CP(enc, "Windows-1254", 1254);
00918     ENC_MACHING_CP(enc, "Windows-1255", 1255);
00919     ENC_MACHING_CP(enc, "Windows-1256", 1256);
00920     ENC_MACHING_CP(enc, "Windows-1257", 1257);
00921     ENC_MACHING_CP(enc, "Windows-1258", 1258);
00922     ENC_MACHING_CP(enc, "Windows-31J", 932);
00923     ENC_MACHING_CP(enc, "Windows-874", 874);
00924     ENC_MACHING_CP(enc, "eucJP-ms", 20932);
00925     return CP_ACP;
00926 }
00927 
00928 static void
00929 failed_load_conv51932(void)
00930 {
00931     rb_raise(eWIN32OLERuntimeError, "fail to load convert function for CP51932");
00932 }
00933 
00934 #ifndef pIMultiLanguage
00935 static void
00936 load_conv_function51932(void)
00937 {
00938     HRESULT hr = E_NOINTERFACE;
00939     void *p;
00940     if (!pIMultiLanguage) {
00941 #if defined(HAVE_TYPE_IMULTILANGUAGE2)
00942         hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
00943                               &IID_IMultiLanguage2, &p);
00944 #elif defined(HAVE_TYPE_IMULTILANGUAGE)
00945         hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
00946                               &IID_IMultiLanguage, &p);
00947 #endif
00948         if (FAILED(hr)) {
00949             failed_load_conv51932();
00950         }
00951         pIMultiLanguage = p;
00952     }
00953 }
00954 #else
00955 #define load_conv_function51932() failed_load_conv51932()
00956 #endif
00957 
00958 #define conv_51932(cp) ((cp) == 51932 && (load_conv_function51932(), 1))
00959 
00960 static void
00961 set_ole_codepage(UINT cp)
00962 {
00963     if (code_page_installed(cp)) {
00964         cWIN32OLE_cp = cp;
00965     } else {
00966         switch(cp) {
00967         case CP_ACP:
00968         case CP_OEMCP:
00969         case CP_MACCP:
00970         case CP_THREAD_ACP:
00971         case CP_SYMBOL:
00972         case CP_UTF7:
00973         case CP_UTF8:
00974             cWIN32OLE_cp = cp;
00975             break;
00976         case 51932:
00977             cWIN32OLE_cp = cp;
00978             load_conv_function51932();
00979             break;
00980         default:
00981             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.");
00982             break;
00983         }
00984     }
00985     cWIN32OLE_enc = ole_cp2encoding(cWIN32OLE_cp);
00986 }
00987 
00988 
00989 static UINT
00990 ole_init_cp(void)
00991 {
00992     UINT cp;
00993     rb_encoding *encdef;
00994     encdef = rb_default_internal_encoding();
00995     if (!encdef) {
00996         encdef = rb_default_external_encoding();
00997     }
00998     cp = ole_encoding2cp(encdef);
00999     set_ole_codepage(cp);
01000     return cp;
01001 }
01002 
01003 struct myCPINFOEX {
01004   UINT MaxCharSize;
01005   BYTE DefaultChar[2];
01006   BYTE LeadByte[12];
01007   WCHAR UnicodeDefaultChar;
01008   UINT CodePage;
01009   char CodePageName[MAX_PATH];
01010 };
01011 
01012 static rb_encoding *
01013 ole_cp2encoding(UINT cp)
01014 {
01015     static BOOL (*pGetCPInfoEx)(UINT, DWORD, struct myCPINFOEX *) = NULL;
01016     struct myCPINFOEX* buf;
01017     VALUE enc_name;
01018     char *enc_cstr;
01019     int idx;
01020 
01021     if (!code_page_installed(cp)) {
01022         switch(cp) {
01023           case CP_ACP:
01024             cp = GetACP();
01025             break;
01026           case CP_OEMCP:
01027             cp = GetOEMCP();
01028             break;
01029           case CP_MACCP:
01030           case CP_THREAD_ACP:
01031             if (!pGetCPInfoEx) {
01032                 pGetCPInfoEx = (BOOL (*)(UINT, DWORD, struct myCPINFOEX *))
01033                     GetProcAddress(GetModuleHandle("kernel32"), "GetCPInfoEx");
01034                 if (!pGetCPInfoEx) {
01035                     pGetCPInfoEx = (void*)-1;
01036                 }
01037             }
01038             buf = ALLOCA_N(struct myCPINFOEX, 1);
01039             ZeroMemory(buf, sizeof(struct myCPINFOEX));
01040             if (pGetCPInfoEx == (void*)-1 || !pGetCPInfoEx(cp, 0, buf)) {
01041                 rb_raise(eWIN32OLERuntimeError, "cannot map codepage to encoding.");
01042                 break;  /* never reach here */
01043             }
01044             cp = buf->CodePage;
01045             break;
01046           case CP_SYMBOL:
01047           case CP_UTF7:
01048           case CP_UTF8:
01049             break;
01050           case 51932:
01051             load_conv_function51932();
01052             break;
01053           default:
01054             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.");
01055             break;
01056         }
01057     }
01058 
01059     enc_name = rb_sprintf("CP%d", cp);
01060     idx = rb_enc_find_index(enc_cstr = StringValueCStr(enc_name));
01061     if (idx < 0)
01062         idx = rb_define_dummy_encoding(enc_cstr);
01063     return rb_enc_from_index(idx);
01064 }
01065 
01066 static char *
01067 ole_wc2mb(LPWSTR pw)
01068 {
01069     LPSTR pm;
01070     UINT size = 0;
01071     if (conv_51932(cWIN32OLE_cp)) {
01072 #ifndef pIMultiLanguage
01073         DWORD dw = 0;
01074         HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage,
01075                 &dw, cWIN32OLE_cp, pw, NULL, NULL, &size);
01076         if (FAILED(hr)) {
01077             ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp);
01078         }
01079         pm = ALLOC_N(char, size + 1);
01080         hr = pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage,
01081                 &dw, cWIN32OLE_cp, pw, NULL, pm, &size);
01082         if (FAILED(hr)) {
01083             ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp);
01084         }
01085         pm[size] = '\0';
01086 #endif
01087         return pm;
01088     }
01089     size = WideCharToMultiByte(cWIN32OLE_cp, 0, pw, -1, NULL, 0, NULL, NULL);
01090     if (size) {
01091         pm = ALLOC_N(char, size + 1);
01092         WideCharToMultiByte(cWIN32OLE_cp, 0, pw, -1, pm, size, NULL, NULL);
01093         pm[size] = '\0';
01094     }
01095     else {
01096         pm = ALLOC_N(char, 1);
01097         *pm = '\0';
01098     }
01099     return pm;
01100 }
01101 
01102 static VALUE
01103 ole_hresult2msg(HRESULT hr)
01104 {
01105     VALUE msg = Qnil;
01106     char *p_msg = NULL;
01107     char *term = NULL;
01108     DWORD dwCount;
01109 
01110     char strhr[100];
01111     sprintf(strhr, "    HRESULT error code:0x%08x\n      ", (unsigned)hr);
01112     msg = rb_str_new2(strhr);
01113     dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
01114                             FORMAT_MESSAGE_FROM_SYSTEM |
01115                             FORMAT_MESSAGE_IGNORE_INSERTS,
01116                             NULL, hr,
01117                             MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
01118                             (LPTSTR)&p_msg, 0, NULL);
01119     if (dwCount == 0) {
01120         dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
01121                                 FORMAT_MESSAGE_FROM_SYSTEM |
01122                                 FORMAT_MESSAGE_IGNORE_INSERTS,
01123                                 NULL, hr, cWIN32OLE_lcid,
01124                                 (LPTSTR)&p_msg, 0, NULL);
01125     }
01126     if (dwCount > 0) {
01127         term = p_msg + strlen(p_msg);
01128         while (p_msg < term) {
01129             term--;
01130             if (*term == '\r' || *term == '\n')
01131                 *term = '\0';
01132             else break;
01133         }
01134         if (p_msg[0] != '\0') {
01135             rb_str_cat2(msg, p_msg);
01136         }
01137     }
01138     LocalFree(p_msg);
01139     return msg;
01140 }
01141 
01142 static void
01143 ole_freeexceptinfo(EXCEPINFO *pExInfo)
01144 {
01145     SysFreeString(pExInfo->bstrDescription);
01146     SysFreeString(pExInfo->bstrSource);
01147     SysFreeString(pExInfo->bstrHelpFile);
01148 }
01149 
01150 static VALUE
01151 ole_excepinfo2msg(EXCEPINFO *pExInfo)
01152 {
01153     char error_code[40];
01154     char *pSource = NULL;
01155     char *pDescription = NULL;
01156     VALUE error_msg;
01157     if(pExInfo->pfnDeferredFillIn != NULL) {
01158         (*pExInfo->pfnDeferredFillIn)(pExInfo);
01159     }
01160     if (pExInfo->bstrSource != NULL) {
01161         pSource = ole_wc2mb(pExInfo->bstrSource);
01162     }
01163     if (pExInfo->bstrDescription != NULL) {
01164         pDescription = ole_wc2mb(pExInfo->bstrDescription);
01165     }
01166     if(pExInfo->wCode == 0) {
01167         sprintf(error_code, "\n    OLE error code:%lX in ", pExInfo->scode);
01168     }
01169     else{
01170         sprintf(error_code, "\n    OLE error code:%u in ", pExInfo->wCode);
01171     }
01172     error_msg = rb_str_new2(error_code);
01173     if(pSource != NULL) {
01174         rb_str_cat(error_msg, pSource, strlen(pSource));
01175     }
01176     else {
01177         rb_str_cat(error_msg, "<Unknown>", 9);
01178     }
01179     rb_str_cat2(error_msg, "\n      ");
01180     if(pDescription != NULL) {
01181         rb_str_cat2(error_msg, pDescription);
01182     }
01183     else {
01184         rb_str_cat2(error_msg, "<No Description>");
01185     }
01186     if(pSource) free(pSource);
01187     if(pDescription) free(pDescription);
01188     ole_freeexceptinfo(pExInfo);
01189     return error_msg;
01190 }
01191 
01192 static void
01193 ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...)
01194 {
01195     va_list args;
01196     VALUE msg;
01197     VALUE err_msg;
01198     va_init_list(args, fmt);
01199     msg = rb_vsprintf(fmt, args);
01200     va_end(args);
01201 
01202     err_msg = ole_hresult2msg(hr);
01203     if(err_msg != Qnil) {
01204         rb_str_cat2(msg, "\n");
01205         rb_str_append(msg, err_msg);
01206     }
01207     rb_exc_raise(rb_exc_new3(ecs, msg));
01208 }
01209 
01210 void
01211 ole_uninitialize(void)
01212 {
01213     if (!g_ole_initialized) return;
01214     OleUninitialize();
01215     g_ole_initialized_set(FALSE);
01216 }
01217 
01218 static void
01219 ole_uninitialize_hook(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass)
01220 {
01221     ole_uninitialize();
01222 }
01223 
01224 static void
01225 ole_initialize(void)
01226 {
01227     HRESULT hr;
01228 
01229     if(!g_uninitialize_hooked) {
01230         rb_add_event_hook(ole_uninitialize_hook, RUBY_EVENT_THREAD_END, Qnil);
01231         g_uninitialize_hooked = TRUE;
01232     }
01233 
01234     if(g_ole_initialized == FALSE) {
01235         hr = OleInitialize(NULL);
01236         if(FAILED(hr)) {
01237             ole_raise(hr, rb_eRuntimeError, "fail: OLE initialize");
01238         }
01239         g_ole_initialized_set(TRUE);
01240 
01241         hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter);
01242         if(FAILED(hr)) {
01243             previous_filter = NULL;
01244             ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter");
01245         }
01246     }
01247 }
01248 
01249 static void
01250 ole_msg_loop() {
01251     MSG msg;
01252     while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
01253         TranslateMessage(&msg);
01254         DispatchMessage(&msg);
01255     }
01256 }
01257 
01258 static void
01259 ole_free(struct oledata *pole)
01260 {
01261     OLE_FREE(pole->pDispatch);
01262     free(pole);
01263 }
01264 
01265 static void
01266 oletypelib_free(struct oletypelibdata *poletypelib)
01267 {
01268     OLE_FREE(poletypelib->pTypeLib);
01269     free(poletypelib);
01270 }
01271 
01272 static void
01273 oletype_free(struct oletypedata *poletype)
01274 {
01275     OLE_FREE(poletype->pTypeInfo);
01276     free(poletype);
01277 }
01278 
01279 static void
01280 olemethod_free(struct olemethoddata *polemethod)
01281 {
01282     OLE_FREE(polemethod->pTypeInfo);
01283     OLE_FREE(polemethod->pOwnerTypeInfo);
01284     free(polemethod);
01285 }
01286 
01287 static void
01288 olevariable_free(struct olevariabledata *polevar)
01289 {
01290     OLE_FREE(polevar->pTypeInfo);
01291     free(polevar);
01292 }
01293 
01294 static void
01295 oleparam_free(struct oleparamdata *pole)
01296 {
01297     OLE_FREE(pole->pTypeInfo);
01298     free(pole);
01299 }
01300 
01301 
01302 static LPWSTR
01303 ole_vstr2wc(VALUE vstr)
01304 {
01305     rb_encoding *enc;
01306     int cp;
01307     UINT size = 0;
01308     LPWSTR pw;
01309     st_data_t data;
01310     enc = rb_enc_get(vstr);
01311 
01312     if (st_lookup(enc2cp_table, (st_data_t)enc, &data)) {
01313         cp = data;
01314     } else {
01315         cp = ole_encoding2cp(enc);
01316         if (code_page_installed(cp) ||
01317             cp == CP_ACP ||
01318             cp == CP_OEMCP ||
01319             cp == CP_MACCP ||
01320             cp == CP_THREAD_ACP ||
01321             cp == CP_SYMBOL ||
01322             cp == CP_UTF7 ||
01323             cp == CP_UTF8 ||
01324             cp == 51932) {
01325             st_insert(enc2cp_table, (st_data_t)enc, (st_data_t)cp);
01326         } else {
01327             rb_raise(eWIN32OLERuntimeError, "not installed Windows codepage(%d) according to `%s'", cp, rb_enc_name(enc));
01328         }
01329     }
01330     if (conv_51932(cp)) {
01331 #ifndef pIMultiLanguage
01332         DWORD dw = 0;
01333         UINT len = RSTRING_LENINT(vstr);
01334         HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
01335                 &dw, cp, RSTRING_PTR(vstr), &len, NULL, &size);
01336         if (FAILED(hr)) {
01337             ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
01338         }
01339         pw = SysAllocStringLen(NULL, size);
01340         len = RSTRING_LEN(vstr);
01341         hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
01342                 &dw, cp, RSTRING_PTR(vstr), &len, pw, &size);
01343         if (FAILED(hr)) {
01344             ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
01345         }
01346 #endif
01347         return pw;
01348     }
01349     size = MultiByteToWideChar(cp, 0, RSTRING_PTR(vstr), RSTRING_LEN(vstr), NULL, 0);
01350     pw = SysAllocStringLen(NULL, size);
01351     MultiByteToWideChar(cp, 0, RSTRING_PTR(vstr), RSTRING_LEN(vstr), pw, size);
01352     return pw;
01353 }
01354 
01355 static LPWSTR
01356 ole_mb2wc(char *pm, int len)
01357 {
01358     UINT size = 0;
01359     LPWSTR pw;
01360 
01361     if (conv_51932(cWIN32OLE_cp)) {
01362 #ifndef pIMultiLanguage
01363         DWORD dw = 0;
01364         UINT n = len;
01365         HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
01366                 &dw, cWIN32OLE_cp, pm, &n, NULL, &size);
01367         if (FAILED(hr)) {
01368             ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cWIN32OLE_cp);
01369         }
01370         pw = SysAllocStringLen(NULL, size);
01371         hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
01372                 &dw, cWIN32OLE_cp, pm, &n, pw, &size);
01373         if (FAILED(hr)) {
01374             ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cWIN32OLE_cp);
01375         }
01376 #endif
01377         return pw;
01378     }
01379     size = MultiByteToWideChar(cWIN32OLE_cp, 0, pm, len, NULL, 0);
01380     pw = SysAllocStringLen(NULL, size - 1);
01381     MultiByteToWideChar(cWIN32OLE_cp, 0, pm, len, pw, size);
01382     return pw;
01383 }
01384 
01385 static VALUE
01386 ole_wc2vstr(LPWSTR pw, BOOL isfree)
01387 {
01388     char *p = ole_wc2mb(pw);
01389     VALUE vstr = rb_enc_str_new(p, strlen(p), cWIN32OLE_enc);
01390     if(isfree)
01391         SysFreeString(pw);
01392     free(p);
01393     return vstr;
01394 }
01395 
01396 static VALUE
01397 ole_ary_m_entry(VALUE val, long *pid)
01398 {
01399     VALUE obj = Qnil;
01400     int i = 0;
01401     obj = val;
01402     while(TYPE(obj) == T_ARRAY) {
01403         obj = rb_ary_entry(obj, pid[i]);
01404         i++;
01405     }
01406     return obj;
01407 }
01408 
01409 static void *
01410 get_ptr_of_variant(VARIANT *pvar)
01411 {
01412     switch(V_VT(pvar)) {
01413     case VT_UI1:
01414         return &V_UI1(pvar);
01415         break;
01416     case VT_I2:
01417         return &V_I2(pvar);
01418         break;
01419     case VT_UI2:
01420         return &V_UI2(pvar);
01421         break;
01422     case VT_I4:
01423         return &V_I4(pvar);
01424         break;
01425     case VT_UI4:
01426         return &V_UI4(pvar);
01427         break;
01428     case VT_R4:
01429         return &V_R4(pvar);
01430         break;
01431     case VT_R8:
01432         return &V_R8(pvar);
01433         break;
01434 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
01435     case VT_I8:
01436         return &V_I8(pvar);
01437         break;
01438     case VT_UI8:
01439         return &V_UI8(pvar);
01440         break;
01441 #endif
01442     case VT_INT:
01443         return &V_INT(pvar);
01444         break;
01445     case VT_UINT:
01446         return &V_UINT(pvar);
01447         break;
01448     case VT_CY:
01449         return &V_CY(pvar);
01450         break;
01451     case VT_DATE:
01452         return &V_DATE(pvar);
01453         break;
01454     case VT_BSTR:
01455         return V_BSTR(pvar);
01456         break;
01457     case VT_DISPATCH:
01458         return V_DISPATCH(pvar);
01459         break;
01460     case VT_ERROR:
01461         return &V_ERROR(pvar);
01462         break;
01463     case VT_BOOL:
01464         return &V_BOOL(pvar);
01465         break;
01466     case VT_UNKNOWN:
01467         return V_UNKNOWN(pvar);
01468         break;
01469     case VT_ARRAY:
01470         return &V_ARRAY(pvar);
01471         break;
01472     default:
01473         return NULL;
01474         break;
01475     }
01476 }
01477 
01478 static VALUE
01479 is_all_index_under(long *pid, long *pub, long dim)
01480 {
01481   long i = 0;
01482   for (i = 0; i < dim; i++) {
01483     if (pid[i] > pub[i]) {
01484       return Qfalse;
01485     }
01486   }
01487   return Qtrue;
01488 }
01489 
01490 static void
01491 ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim,  VARTYPE vt)
01492 {
01493     VALUE val1;
01494     HRESULT hr = S_OK;
01495     VARIANT var;
01496     VOID *p = NULL;
01497     long i = n;
01498     while(i >= 0) {
01499         val1 = ole_ary_m_entry(val, pid);
01500         VariantInit(&var);
01501         p = val2variant_ptr(val1, &var, vt);
01502         if (is_all_index_under(pid, pub, dim) == Qtrue) {
01503             if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
01504                 (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
01505                 rb_raise(eWIN32OLERuntimeError, "element of array does not have IDispatch or IUnknown Interface");
01506             }
01507             hr = SafeArrayPutElement(psa, pid, p);
01508         }
01509         if (FAILED(hr)) {
01510             ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement");
01511         }
01512         pid[i] += 1;
01513         if (pid[i] > pub[i]) {
01514             pid[i] = 0;
01515             i -= 1;
01516         } else {
01517             i = dim - 1;
01518         }
01519     }
01520 }
01521 
01522 static long
01523 dimension(VALUE val) {
01524     long dim = 0;
01525     long dim1 = 0;
01526     long len = 0;
01527     long i = 0;
01528     if (TYPE(val) == T_ARRAY) {
01529         len = RARRAY_LEN(val);
01530         for (i = 0; i < len; i++) {
01531             dim1 = dimension(rb_ary_entry(val, i));
01532             if (dim < dim1) {
01533                 dim = dim1;
01534             }
01535         }
01536         dim += 1;
01537     }
01538     return dim;
01539 }
01540 
01541 static long
01542 ary_len_of_dim(VALUE ary, long dim) {
01543     long ary_len = 0;
01544     long ary_len1 = 0;
01545     long len = 0;
01546     long i = 0;
01547     VALUE val;
01548     if (dim == 0) {
01549         if (TYPE(ary) == T_ARRAY) {
01550             ary_len = RARRAY_LEN(ary);
01551         }
01552     } else {
01553         if (TYPE(ary) == T_ARRAY) {
01554             len = RARRAY_LEN(ary);
01555             for (i = 0; i < len; i++) {
01556                 val = rb_ary_entry(ary, i);
01557                 ary_len1 = ary_len_of_dim(val, dim-1);
01558                 if (ary_len < ary_len1) {
01559                     ary_len = ary_len1;
01560                 }
01561             }
01562         }
01563     }
01564     return ary_len;
01565 }
01566 
01567 static HRESULT
01568 ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt)
01569 {
01570     long dim = 0;
01571     int  i = 0;
01572     HRESULT hr = S_OK;
01573 
01574     SAFEARRAYBOUND *psab = NULL;
01575     SAFEARRAY *psa = NULL;
01576     long      *pub, *pid;
01577 
01578     Check_Type(val, T_ARRAY);
01579 
01580     dim = dimension(val);
01581 
01582     psab = ALLOC_N(SAFEARRAYBOUND, dim);
01583     pub  = ALLOC_N(long, dim);
01584     pid  = ALLOC_N(long, dim);
01585 
01586     if(!psab || !pub || !pid) {
01587         if(pub) free(pub);
01588         if(psab) free(psab);
01589         if(pid) free(pid);
01590         rb_raise(rb_eRuntimeError, "memory allocation error");
01591     }
01592 
01593     for (i = 0; i < dim; i++) {
01594         psab[i].cElements = ary_len_of_dim(val, i);
01595         psab[i].lLbound = 0;
01596         pub[i] = psab[i].cElements - 1;
01597         pid[i] = 0;
01598     }
01599     /* Create and fill VARIANT array */
01600     if ((vt & ~VT_BYREF) == VT_ARRAY) {
01601         vt = (vt | VT_VARIANT);
01602     }
01603     psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
01604     if (psa == NULL)
01605         hr = E_OUTOFMEMORY;
01606     else
01607         hr = SafeArrayLock(psa);
01608     if (SUCCEEDED(hr)) {
01609         ole_set_safe_array(dim-1, psa, pid, pub, val, dim, (VARTYPE)(vt & VT_TYPEMASK));
01610         hr = SafeArrayUnlock(psa);
01611     }
01612 
01613     if(pub) free(pub);
01614     if(psab) free(psab);
01615     if(pid) free(pid);
01616 
01617     if (SUCCEEDED(hr)) {
01618         V_VT(var) = vt;
01619         V_ARRAY(var) = psa;
01620     }
01621     else {
01622         if (psa != NULL)
01623             SafeArrayDestroy(psa);
01624     }
01625     return hr;
01626 }
01627 
01628 static void
01629 ole_val2variant(VALUE val, VARIANT *var)
01630 {
01631     struct oledata *pole;
01632     struct olevariantdata *pvar;
01633     if(rb_obj_is_kind_of(val, cWIN32OLE)) {
01634         Data_Get_Struct(val, struct oledata, pole);
01635         OLE_ADDREF(pole->pDispatch);
01636         V_VT(var) = VT_DISPATCH;
01637         V_DISPATCH(var) = pole->pDispatch;
01638         return;
01639     }
01640     if (rb_obj_is_kind_of(val, cWIN32OLE_VARIANT)) {
01641         Data_Get_Struct(val, struct olevariantdata, pvar);
01642         VariantCopy(var, &(pvar->var));
01643         return;
01644     }
01645 
01646     if (rb_obj_is_kind_of(val, rb_cTime)) {
01647         V_VT(var) = VT_DATE;
01648         V_DATE(var) = rbtime2vtdate(val);
01649         return;
01650     }
01651     switch (TYPE(val)) {
01652     case T_ARRAY:
01653         ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY);
01654         break;
01655     case T_STRING:
01656         V_VT(var) = VT_BSTR;
01657         V_BSTR(var) = ole_vstr2wc(val);
01658         break;
01659     case T_FIXNUM:
01660         V_VT(var) = VT_I4;
01661         V_I4(var) = NUM2INT(val);
01662         break;
01663     case T_BIGNUM:
01664         V_VT(var) = VT_R8;
01665         V_R8(var) = rb_big2dbl(val);
01666         break;
01667     case T_FLOAT:
01668         V_VT(var) = VT_R8;
01669         V_R8(var) = NUM2DBL(val);
01670         break;
01671     case T_TRUE:
01672         V_VT(var) = VT_BOOL;
01673         V_BOOL(var) = VARIANT_TRUE;
01674         break;
01675     case T_FALSE:
01676         V_VT(var) = VT_BOOL;
01677         V_BOOL(var) = VARIANT_FALSE;
01678         break;
01679     case T_NIL:
01680         if (g_nil_to == VT_ERROR) {
01681             V_VT(var) = VT_ERROR;
01682             V_ERROR(var) = DISP_E_PARAMNOTFOUND;
01683         }else {
01684             V_VT(var) = VT_EMPTY;
01685         }
01686         break;
01687     default:
01688         V_VT(var) = VT_DISPATCH;
01689         V_DISPATCH(var) = val2dispatch(val);
01690         break;
01691     }
01692 }
01693 
01694 static void
01695 ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt)
01696 {
01697     if (val == Qnil) {
01698         if (vt == VT_VARIANT) {
01699             ole_val2variant2(val, var);
01700         } else {
01701             V_VT(var) = (vt & ~VT_BYREF);
01702             if (V_VT(var) == VT_DISPATCH) {
01703                 V_DISPATCH(var) = NULL;
01704             } else if (V_VT(var) == VT_UNKNOWN) {
01705                 V_UNKNOWN(var) = NULL;
01706             }
01707         }
01708         return;
01709     }
01710 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
01711     switch(vt & ~VT_BYREF) {
01712     case VT_I8:
01713         V_VT(var) = VT_I8;
01714         V_I8(var) = NUM2I8 (val);
01715         break;
01716     case VT_UI8:
01717         V_VT(var) = VT_UI8;
01718         V_UI8(var) = NUM2UI8(val);
01719         break;
01720     default:
01721         ole_val2variant2(val, var);
01722         break;
01723     }
01724 #else  /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
01725     ole_val2variant2(val, var);
01726 #endif
01727 }
01728 
01729 static void
01730 ole_val2ptr_variant(VALUE val, VARIANT *var)
01731 {
01732     switch (TYPE(val)) {
01733     case T_STRING:
01734         if (V_VT(var) == (VT_BSTR | VT_BYREF)) {
01735             *V_BSTRREF(var) = ole_vstr2wc(val);
01736         }
01737         break;
01738     case T_FIXNUM:
01739         switch(V_VT(var)) {
01740         case (VT_UI1 | VT_BYREF) :
01741             *V_UI1REF(var) = NUM2CHR(val);
01742             break;
01743         case (VT_I2 | VT_BYREF) :
01744             *V_I2REF(var) = (short)NUM2INT(val);
01745             break;
01746         case (VT_I4 | VT_BYREF) :
01747             *V_I4REF(var) = NUM2INT(val);
01748             break;
01749         case (VT_R4 | VT_BYREF) :
01750             *V_R4REF(var) = (float)NUM2INT(val);
01751             break;
01752         case (VT_R8 | VT_BYREF) :
01753             *V_R8REF(var) = NUM2INT(val);
01754             break;
01755         default:
01756             break;
01757         }
01758         break;
01759     case T_FLOAT:
01760         switch(V_VT(var)) {
01761         case (VT_I2 | VT_BYREF) :
01762             *V_I2REF(var) = (short)NUM2INT(val);
01763             break;
01764         case (VT_I4 | VT_BYREF) :
01765             *V_I4REF(var) = NUM2INT(val);
01766             break;
01767         case (VT_R4 | VT_BYREF) :
01768             *V_R4REF(var) = (float)NUM2DBL(val);
01769             break;
01770         case (VT_R8 | VT_BYREF) :
01771             *V_R8REF(var) = NUM2DBL(val);
01772             break;
01773         default:
01774             break;
01775         }
01776         break;
01777     case T_BIGNUM:
01778         if (V_VT(var) == (VT_R8 | VT_BYREF)) {
01779             *V_R8REF(var) = rb_big2dbl(val);
01780         }
01781         break;
01782     case T_TRUE:
01783         if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
01784             *V_BOOLREF(var) = VARIANT_TRUE;
01785         }
01786         break;
01787     case T_FALSE:
01788         if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
01789             *V_BOOLREF(var) = VARIANT_FALSE;
01790         }
01791         break;
01792     default:
01793         break;
01794     }
01795 }
01796 
01797 static void
01798 ole_set_byref(VARIANT *realvar, VARIANT *var,  VARTYPE vt)
01799 {
01800     V_VT(var) = vt;
01801     if (vt == (VT_VARIANT|VT_BYREF)) {
01802         V_VARIANTREF(var) = realvar;
01803     } else {
01804         if (V_VT(realvar) != (vt & ~VT_BYREF)) {
01805             rb_raise(eWIN32OLERuntimeError, "variant type mismatch");
01806         }
01807         switch(vt & ~VT_BYREF) {
01808         case VT_I1:
01809             V_I1REF(var) = &V_I1(realvar);
01810             break;
01811         case VT_UI1:
01812             V_UI1REF(var) = &V_UI1(realvar);
01813             break;
01814         case VT_I2:
01815             V_I2REF(var) = &V_I2(realvar);
01816             break;
01817         case VT_UI2:
01818             V_UI2REF(var) = &V_UI2(realvar);
01819             break;
01820         case VT_I4:
01821             V_I4REF(var) = &V_I4(realvar);
01822             break;
01823         case VT_UI4:
01824             V_UI4REF(var) = &V_UI4(realvar);
01825             break;
01826         case VT_R4:
01827             V_R4REF(var) = &V_R4(realvar);
01828             break;
01829         case VT_R8:
01830             V_R8REF(var) = &V_R8(realvar);
01831             break;
01832 
01833 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
01834 #ifdef V_I8REF
01835         case VT_I8:
01836             V_I8REF(var) = &V_I8(realvar);
01837             break;
01838 #endif
01839 #ifdef V_UI8REF
01840         case VT_UI8:
01841             V_UI8REF(var) = &V_UI8(realvar);
01842             break;
01843 #endif
01844 #endif
01845         case VT_INT:
01846             V_INTREF(var) = &V_INT(realvar);
01847             break;
01848 
01849         case VT_UINT:
01850             V_UINTREF(var) = &V_UINT(realvar);
01851             break;
01852 
01853         case VT_CY:
01854             V_CYREF(var) = &V_CY(realvar);
01855             break;
01856         case VT_DATE:
01857             V_DATEREF(var) = &V_DATE(realvar);
01858             break;
01859         case VT_BSTR:
01860             V_BSTRREF(var) = &V_BSTR(realvar);
01861             break;
01862         case VT_DISPATCH:
01863             V_DISPATCHREF(var) = &V_DISPATCH(realvar);
01864             break;
01865         case VT_ERROR:
01866             V_ERRORREF(var) = &V_ERROR(realvar);
01867             break;
01868         case VT_BOOL:
01869             V_BOOLREF(var) = &V_BOOL(realvar);
01870             break;
01871         case VT_UNKNOWN:
01872             V_UNKNOWNREF(var) = &V_UNKNOWN(realvar);
01873             break;
01874         case VT_ARRAY:
01875             V_ARRAYREF(var) = &V_ARRAY(realvar);
01876             break;
01877         default:
01878             rb_raise(eWIN32OLERuntimeError, "unknown type specified(setting BYREF):%d", vt);
01879             break;
01880         }
01881     }
01882 }
01883 
01884 static void
01885 ole_val2olevariantdata(VALUE val, VARTYPE vt, struct olevariantdata *pvar)
01886 {
01887     HRESULT hr = S_OK;
01888 
01889     if (((vt & ~VT_BYREF) ==  (VT_ARRAY | VT_UI1)) && TYPE(val) == T_STRING) {
01890         long len = RSTRING_LEN(val);
01891         void *pdest = NULL;
01892         SAFEARRAY *p = NULL;
01893         SAFEARRAY *psa = SafeArrayCreateVector(VT_UI1, 0, len);
01894         if (!psa) {
01895             rb_raise(rb_eRuntimeError, "fail to SafeArrayCreateVector");
01896         }
01897         hr = SafeArrayAccessData(psa, &pdest);
01898         if (SUCCEEDED(hr)) {
01899             memcpy(pdest, RSTRING_PTR(val), len);
01900             SafeArrayUnaccessData(psa);
01901             V_VT(&(pvar->realvar)) = (vt & ~VT_BYREF);
01902             p = V_ARRAY(&(pvar->realvar));
01903             if (p != NULL) {
01904                 SafeArrayDestroy(p);
01905             }
01906             V_ARRAY(&(pvar->realvar)) = psa;
01907             if (vt & VT_BYREF) {
01908                 V_VT(&(pvar->var)) = vt;
01909                 V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
01910             } else {
01911                 hr = VariantCopy(&(pvar->var), &(pvar->realvar));
01912             }
01913         } else {
01914             if (psa)
01915                 SafeArrayDestroy(psa);
01916         }
01917     } else if (vt & VT_ARRAY) {
01918         if (val == Qnil) {
01919             V_VT(&(pvar->var)) = vt;
01920             if (vt & VT_BYREF) {
01921                 V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
01922             }
01923         } else {
01924             hr = ole_val_ary2variant_ary(val, &(pvar->realvar), (VARTYPE)(vt & ~VT_BYREF));
01925             if (SUCCEEDED(hr)) {
01926                 if (vt & VT_BYREF) {
01927                     V_VT(&(pvar->var)) = vt;
01928                     V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
01929                 } else {
01930                     hr = VariantCopy(&(pvar->var), &(pvar->realvar));
01931                 }
01932             }
01933         }
01934 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
01935     } else if ( (vt & ~VT_BYREF) == VT_I8 || (vt & ~VT_BYREF) == VT_UI8) {
01936         ole_val2variant_ex(val, &(pvar->realvar), (vt & ~VT_BYREF));
01937         ole_val2variant_ex(val, &(pvar->var), (vt & ~VT_BYREF));
01938         V_VT(&(pvar->var)) = vt;
01939         if (vt & VT_BYREF) {
01940             ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
01941         }
01942 #endif
01943     } else {
01944         if (val == Qnil) {
01945             V_VT(&(pvar->var)) = vt;
01946             if (vt == (VT_BYREF | VT_VARIANT)) {
01947                 ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
01948             } else {
01949                 V_VT(&(pvar->realvar)) = vt & ~VT_BYREF;
01950                 if (vt & VT_BYREF) {
01951                     ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
01952                 }
01953             }
01954         } else {
01955             ole_val2variant_ex(val, &(pvar->realvar), (VARTYPE)(vt & ~VT_BYREF));
01956             if (vt == (VT_BYREF | VT_VARIANT)) {
01957                 ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
01958             } else if (vt & VT_BYREF) {
01959                 if ( (vt & ~VT_BYREF) != V_VT(&(pvar->realvar))) {
01960                     hr = VariantChangeTypeEx(&(pvar->realvar), &(pvar->realvar),
01961                             cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF));
01962                 }
01963                 if (SUCCEEDED(hr)) {
01964                     ole_set_byref(&(pvar->realvar), &(pvar->var), vt);
01965                 }
01966             } else {
01967                 if (vt == V_VT(&(pvar->realvar))) {
01968                     hr = VariantCopy(&(pvar->var), &(pvar->realvar));
01969                 } else {
01970                     hr = VariantChangeTypeEx(&(pvar->var), &(pvar->realvar),
01971                             cWIN32OLE_lcid, 0, vt);
01972                 }
01973             }
01974         }
01975     }
01976     if (FAILED(hr)) {
01977         ole_raise(hr, eWIN32OLERuntimeError, "failed to change type");
01978     }
01979 }
01980 
01981 static void
01982 ole_val2variant2(VALUE val, VARIANT *var)
01983 {
01984     g_nil_to = VT_EMPTY;
01985     ole_val2variant(val, var);
01986     g_nil_to = VT_ERROR;
01987 }
01988 
01989 static VALUE
01990 make_inspect(const char *class_name, VALUE detail)
01991 {
01992     VALUE str;
01993     str = rb_str_new2("#<");
01994     rb_str_cat2(str, class_name);
01995     rb_str_cat2(str, ":");
01996     rb_str_concat(str, detail);
01997     rb_str_cat2(str, ">");
01998     return str;
01999 }
02000 
02001 static VALUE
02002 default_inspect(VALUE self, const char *class_name)
02003 {
02004     VALUE detail = rb_funcall(self, rb_intern("to_s"), 0);
02005     return make_inspect(class_name, detail);
02006 }
02007 
02008 static VALUE
02009 ole_set_member(VALUE self, IDispatch *dispatch)
02010 {
02011     struct oledata *pole;
02012     Data_Get_Struct(self, struct oledata, pole);
02013     if (pole->pDispatch) {
02014         OLE_RELEASE(pole->pDispatch);
02015         pole->pDispatch = NULL;
02016     }
02017     pole->pDispatch = dispatch;
02018     return self;
02019 }
02020 
02021 
02022 static VALUE
02023 fole_s_allocate(VALUE klass)
02024 {
02025     struct oledata *pole;
02026     VALUE obj;
02027     ole_initialize();
02028     obj = Data_Make_Struct(klass,struct oledata,0,ole_free,pole);
02029     pole->pDispatch = NULL;
02030     return obj;
02031 }
02032 
02033 static VALUE
02034 create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv)
02035 {
02036     VALUE obj = fole_s_allocate(klass);
02037     ole_set_member(obj, pDispatch);
02038     return obj;
02039 }
02040 
02041 static VALUE
02042 ary_new_dim(VALUE myary, long *pid, long *plb, long dim) {
02043     long i;
02044     VALUE obj = Qnil;
02045     VALUE pobj = Qnil;
02046     long *ids = ALLOC_N(long, dim);
02047     if (!ids) {
02048         rb_raise(rb_eRuntimeError, "memory allocation error");
02049     }
02050     for(i = 0; i < dim; i++) {
02051         ids[i] = pid[i] - plb[i];
02052     }
02053     obj = myary;
02054     pobj = myary;
02055     for(i = 0; i < dim-1; i++) {
02056         obj = rb_ary_entry(pobj, ids[i]);
02057         if (obj == Qnil) {
02058             rb_ary_store(pobj, ids[i], rb_ary_new());
02059         }
02060         obj = rb_ary_entry(pobj, ids[i]);
02061         pobj = obj;
02062     }
02063     if (ids) free(ids);
02064     return obj;
02065 }
02066 
02067 static void
02068 ary_store_dim(VALUE myary, long *pid, long *plb, long dim, VALUE val) {
02069     long id = pid[dim - 1] - plb[dim - 1];
02070     VALUE obj = ary_new_dim(myary, pid, plb, dim);
02071     rb_ary_store(obj, id, val);
02072 }
02073 
02074 static VALUE
02075 ole_variant2val(VARIANT *pvar)
02076 {
02077     VALUE obj = Qnil;
02078     HRESULT hr;
02079     while ( V_VT(pvar) == (VT_BYREF | VT_VARIANT) )
02080         pvar = V_VARIANTREF(pvar);
02081 
02082     if(V_ISARRAY(pvar)) {
02083         SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar);
02084         UINT i = 0;
02085         long *pid, *plb, *pub;
02086         VARIANT variant;
02087         VALUE val;
02088         UINT dim = 0;
02089         if (!psa) {
02090             return obj;
02091         }
02092         dim = SafeArrayGetDim(psa);
02093         VariantInit(&variant);
02094         V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF;
02095 
02096         pid = ALLOC_N(long, dim);
02097         plb = ALLOC_N(long, dim);
02098         pub = ALLOC_N(long, dim);
02099 
02100         if(!pid || !plb || !pub) {
02101             if(pid) free(pid);
02102             if(plb) free(plb);
02103             if(pub) free(pub);
02104             rb_raise(rb_eRuntimeError, "memory allocation error");
02105         }
02106 
02107         for(i = 0; i < dim; ++i) {
02108             SafeArrayGetLBound(psa, i+1, &plb[i]);
02109             SafeArrayGetLBound(psa, i+1, &pid[i]);
02110             SafeArrayGetUBound(psa, i+1, &pub[i]);
02111         }
02112         hr = SafeArrayLock(psa);
02113         if (SUCCEEDED(hr)) {
02114             obj = rb_ary_new();
02115             i = 0;
02116             while (i < dim) {
02117                 ary_new_dim(obj, pid, plb, dim);
02118                 hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
02119                 if (SUCCEEDED(hr)) {
02120                     val = ole_variant2val(&variant);
02121                     ary_store_dim(obj, pid, plb, dim, val);
02122                 }
02123                 for (i = 0; i < dim; ++i) {
02124                     if (++pid[i] <= pub[i])
02125                         break;
02126                     pid[i] = plb[i];
02127                 }
02128             }
02129             SafeArrayUnlock(psa);
02130         }
02131         if(pid) free(pid);
02132         if(plb) free(plb);
02133         if(pub) free(pub);
02134         return obj;
02135     }
02136     switch(V_VT(pvar) & ~VT_BYREF){
02137     case VT_EMPTY:
02138         break;
02139     case VT_NULL:
02140         break;
02141     case VT_I1:
02142         if(V_ISBYREF(pvar))
02143             obj = INT2NUM((long)*V_I1REF(pvar));
02144         else
02145             obj = INT2NUM((long)V_I1(pvar));
02146         break;
02147 
02148     case VT_UI1:
02149         if(V_ISBYREF(pvar))
02150             obj = INT2NUM((long)*V_UI1REF(pvar));
02151         else
02152             obj = INT2NUM((long)V_UI1(pvar));
02153         break;
02154 
02155     case VT_I2:
02156         if(V_ISBYREF(pvar))
02157             obj = INT2NUM((long)*V_I2REF(pvar));
02158         else
02159             obj = INT2NUM((long)V_I2(pvar));
02160         break;
02161 
02162     case VT_UI2:
02163         if(V_ISBYREF(pvar))
02164             obj = INT2NUM((long)*V_UI2REF(pvar));
02165         else
02166             obj = INT2NUM((long)V_UI2(pvar));
02167         break;
02168 
02169     case VT_I4:
02170         if(V_ISBYREF(pvar))
02171             obj = INT2NUM((long)*V_I4REF(pvar));
02172         else
02173             obj = INT2NUM((long)V_I4(pvar));
02174         break;
02175 
02176     case VT_UI4:
02177         if(V_ISBYREF(pvar))
02178             obj = INT2NUM((long)*V_UI4REF(pvar));
02179         else
02180             obj = INT2NUM((long)V_UI4(pvar));
02181         break;
02182 
02183     case VT_INT:
02184         if(V_ISBYREF(pvar))
02185             obj = INT2NUM((long)*V_INTREF(pvar));
02186         else
02187             obj = INT2NUM((long)V_INT(pvar));
02188         break;
02189 
02190     case VT_UINT:
02191         if(V_ISBYREF(pvar))
02192             obj = INT2NUM((long)*V_UINTREF(pvar));
02193         else
02194             obj = INT2NUM((long)V_UINT(pvar));
02195         break;
02196 
02197 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
02198     case VT_I8:
02199         if(V_ISBYREF(pvar))
02200 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
02201 #ifdef V_I8REF
02202             obj = I8_2_NUM(*V_I8REF(pvar));
02203 #endif
02204 #else
02205             obj = Qnil;
02206 #endif
02207         else
02208             obj = I8_2_NUM(V_I8(pvar));
02209         break;
02210     case VT_UI8:
02211         if(V_ISBYREF(pvar))
02212 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
02213 #ifdef V_UI8REF
02214             obj = UI8_2_NUM(*V_UI8REF(pvar));
02215 #endif
02216 #else
02217             obj = Qnil;
02218 #endif
02219         else
02220             obj = UI8_2_NUM(V_UI8(pvar));
02221         break;
02222 #endif  /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
02223 
02224     case VT_R4:
02225         if(V_ISBYREF(pvar))
02226             obj = rb_float_new(*V_R4REF(pvar));
02227         else
02228             obj = rb_float_new(V_R4(pvar));
02229         break;
02230 
02231     case VT_R8:
02232         if(V_ISBYREF(pvar))
02233             obj = rb_float_new(*V_R8REF(pvar));
02234         else
02235             obj = rb_float_new(V_R8(pvar));
02236         break;
02237 
02238     case VT_BSTR:
02239     {
02240         if(V_ISBYREF(pvar))
02241             obj = ole_wc2vstr(*V_BSTRREF(pvar), FALSE);
02242         else
02243             obj = ole_wc2vstr(V_BSTR(pvar), FALSE);
02244         break;
02245     }
02246 
02247     case VT_ERROR:
02248         if(V_ISBYREF(pvar))
02249             obj = INT2NUM(*V_ERRORREF(pvar));
02250         else
02251             obj = INT2NUM(V_ERROR(pvar));
02252         break;
02253 
02254     case VT_BOOL:
02255         if (V_ISBYREF(pvar))
02256             obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse);
02257         else
02258             obj = (V_BOOL(pvar) ? Qtrue : Qfalse);
02259         break;
02260 
02261     case VT_DISPATCH:
02262     {
02263         IDispatch *pDispatch;
02264 
02265         if (V_ISBYREF(pvar))
02266             pDispatch = *V_DISPATCHREF(pvar);
02267         else
02268             pDispatch = V_DISPATCH(pvar);
02269 
02270         if (pDispatch != NULL ) {
02271             OLE_ADDREF(pDispatch);
02272             obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
02273         }
02274         break;
02275     }
02276 
02277     case VT_UNKNOWN:
02278     {
02279         /* get IDispatch interface from IUnknown interface */
02280         IUnknown *punk;
02281         IDispatch *pDispatch;
02282         void *p;
02283         HRESULT hr;
02284 
02285         if (V_ISBYREF(pvar))
02286             punk = *V_UNKNOWNREF(pvar);
02287         else
02288             punk = V_UNKNOWN(pvar);
02289 
02290         if(punk != NULL) {
02291            hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch, &p);
02292            if(SUCCEEDED(hr)) {
02293                pDispatch = p;
02294                obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
02295            }
02296         }
02297         break;
02298     }
02299 
02300     case VT_DATE:
02301     {
02302         DATE date;
02303         if(V_ISBYREF(pvar))
02304             date = *V_DATEREF(pvar);
02305         else
02306             date = V_DATE(pvar);
02307 
02308         obj =  vtdate2rbtime(date);
02309         break;
02310     }
02311     case VT_CY:
02312     default:
02313         {
02314         HRESULT hr;
02315         VARIANT variant;
02316         VariantInit(&variant);
02317         hr = VariantChangeTypeEx(&variant, pvar,
02318                                   cWIN32OLE_lcid, 0, VT_BSTR);
02319         if (SUCCEEDED(hr) && V_VT(&variant) == VT_BSTR) {
02320             obj = ole_wc2vstr(V_BSTR(&variant), FALSE);
02321         }
02322         VariantClear(&variant);
02323         break;
02324         }
02325     }
02326     return obj;
02327 }
02328 
02329 static LONG
02330 reg_open_key(HKEY hkey, const char *name, HKEY *phkey)
02331 {
02332     return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey);
02333 }
02334 
02335 static LONG
02336 reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey)
02337 {
02338     return reg_open_key(hkey, StringValuePtr(key), phkey);
02339 }
02340 
02341 static VALUE
02342 reg_enum_key(HKEY hkey, DWORD i)
02343 {
02344     char buf[BUFSIZ + 1];
02345     DWORD size_buf = sizeof(buf);
02346     FILETIME ft;
02347     LONG err = RegEnumKeyEx(hkey, i, buf, &size_buf,
02348                             NULL, NULL, NULL, &ft);
02349     if(err == ERROR_SUCCESS) {
02350         buf[BUFSIZ] = '\0';
02351         return rb_str_new2(buf);
02352     }
02353     return Qnil;
02354 }
02355 
02356 static VALUE
02357 reg_get_val(HKEY hkey, const char *subkey)
02358 {
02359     char *pbuf;
02360     DWORD dwtype = 0;
02361     DWORD size = 0;
02362     VALUE val = Qnil;
02363     LONG err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, NULL, &size);
02364 
02365     if (err == ERROR_SUCCESS) {
02366         pbuf = ALLOC_N(char, size + 1);
02367         err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, (BYTE *)pbuf, &size);
02368         if (err == ERROR_SUCCESS) {
02369             pbuf[size] = '\0';
02370             if (dwtype == REG_EXPAND_SZ) {
02371                 char* pbuf2 = (char *)pbuf;
02372                 DWORD len = ExpandEnvironmentStrings(pbuf2, NULL, 0);
02373                 pbuf = ALLOC_N(char, len + 1);
02374                 ExpandEnvironmentStrings(pbuf2, pbuf, len + 1);
02375                 free(pbuf2);
02376             }
02377             val = rb_str_new2((char *)pbuf);
02378         }
02379         free(pbuf);
02380     }
02381     return val;
02382 }
02383 
02384 static VALUE
02385 reg_get_val2(HKEY hkey, const char *subkey)
02386 {
02387     HKEY hsubkey;
02388     LONG err;
02389     VALUE val = Qnil;
02390     err = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &hsubkey);
02391     if (err == ERROR_SUCCESS) {
02392         val = reg_get_val(hsubkey, NULL);
02393         RegCloseKey(hsubkey);
02394     }
02395     if (val == Qnil) {
02396         val = reg_get_val(hkey, subkey);
02397     }
02398     return val;
02399 }
02400 
02401 static VALUE
02402 reg_get_typelib_file_path(HKEY hkey)
02403 {
02404     VALUE path = Qnil;
02405     path = reg_get_val2(hkey, "win64");
02406     if (path != Qnil) {
02407         return path;
02408     }
02409     path = reg_get_val2(hkey, "win32");
02410     if (path != Qnil) {
02411         return path;
02412     }
02413     path = reg_get_val2(hkey, "win16");
02414     return path;
02415 }
02416 
02417 static VALUE
02418 typelib_file_from_clsid(VALUE ole)
02419 {
02420     HKEY hroot, hclsid;
02421     LONG err;
02422     VALUE typelib;
02423     char path[MAX_PATH + 1];
02424 
02425     err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hroot);
02426     if (err != ERROR_SUCCESS) {
02427         return Qnil;
02428     }
02429     err = reg_open_key(hroot, StringValuePtr(ole), &hclsid);
02430     if (err != ERROR_SUCCESS) {
02431         RegCloseKey(hroot);
02432         return Qnil;
02433     }
02434     typelib = reg_get_val2(hclsid, "InprocServer32");
02435     RegCloseKey(hroot);
02436     RegCloseKey(hclsid);
02437     if (typelib != Qnil) {
02438         ExpandEnvironmentStrings(StringValuePtr(typelib), path, sizeof(path));
02439         path[MAX_PATH] = '\0';
02440         typelib = rb_str_new2(path);
02441     }
02442     return typelib;
02443 }
02444 
02445 static VALUE
02446 typelib_file_from_typelib(VALUE ole)
02447 {
02448     HKEY htypelib, hclsid, hversion, hlang;
02449     double fver;
02450     DWORD i, j, k;
02451     LONG err;
02452     BOOL found = FALSE;
02453     VALUE typelib;
02454     VALUE file = Qnil;
02455     VALUE clsid;
02456     VALUE ver;
02457     VALUE lang;
02458 
02459     err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
02460     if(err != ERROR_SUCCESS) {
02461         return Qnil;
02462     }
02463     for(i = 0; !found; i++) {
02464         clsid = reg_enum_key(htypelib, i);
02465         if (clsid == Qnil)
02466             break;
02467         err = reg_open_vkey(htypelib, clsid, &hclsid);
02468         if (err != ERROR_SUCCESS)
02469             continue;
02470         fver = 0;
02471         for(j = 0; !found; j++) {
02472             ver = reg_enum_key(hclsid, j);
02473             if (ver == Qnil)
02474                 break;
02475             err = reg_open_vkey(hclsid, ver, &hversion);
02476                         if (err != ERROR_SUCCESS || fver > atof(StringValuePtr(ver)))
02477                 continue;
02478             fver = atof(StringValuePtr(ver));
02479             typelib = reg_get_val(hversion, NULL);
02480             if (typelib == Qnil)
02481                 continue;
02482             if (rb_str_cmp(typelib, ole) == 0) {
02483                 for(k = 0; !found; k++) {
02484                     lang = reg_enum_key(hversion, k);
02485                     if (lang == Qnil)
02486                         break;
02487                     err = reg_open_vkey(hversion, lang, &hlang);
02488                     if (err == ERROR_SUCCESS) {
02489                         if ((file = reg_get_typelib_file_path(hlang)) != Qnil)
02490                             found = TRUE;
02491                         RegCloseKey(hlang);
02492                     }
02493                 }
02494             }
02495             RegCloseKey(hversion);
02496         }
02497         RegCloseKey(hclsid);
02498     }
02499     RegCloseKey(htypelib);
02500     return  file;
02501 }
02502 
02503 static VALUE
02504 typelib_file(VALUE ole)
02505 {
02506     VALUE file = typelib_file_from_clsid(ole);
02507     if (file != Qnil) {
02508         return file;
02509     }
02510     return typelib_file_from_typelib(ole);
02511 }
02512 
02513 static void
02514 ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self)
02515 {
02516     unsigned int count;
02517     unsigned int index;
02518     int iVar;
02519     ITypeInfo *pTypeInfo;
02520     TYPEATTR  *pTypeAttr;
02521     VARDESC   *pVarDesc;
02522     HRESULT hr;
02523     unsigned int len;
02524     BSTR bstr;
02525     char *pName = NULL;
02526     VALUE val;
02527     VALUE constant;
02528     ID id;
02529     constant = rb_hash_new();
02530     count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
02531     for (index = 0; index < count; index++) {
02532         hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, index, &pTypeInfo);
02533         if (FAILED(hr))
02534             continue;
02535         hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
02536         if(FAILED(hr)) {
02537             OLE_RELEASE(pTypeInfo);
02538             continue;
02539         }
02540         for(iVar = 0; iVar < pTypeAttr->cVars; iVar++) {
02541             hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, iVar, &pVarDesc);
02542             if(FAILED(hr))
02543                 continue;
02544             if(pVarDesc->varkind == VAR_CONST &&
02545                !(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
02546                                         VARFLAG_FRESTRICTED |
02547                                         VARFLAG_FNONBROWSABLE))) {
02548                 hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
02549                                                  1, &len);
02550                 if(FAILED(hr) || len == 0 || !bstr)
02551                     continue;
02552                 pName = ole_wc2mb(bstr);
02553                 val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
02554                 *pName = toupper((int)*pName);
02555                 id = rb_intern(pName);
02556                 if (rb_is_const_id(id)) {
02557                     rb_define_const(klass, pName, val);
02558                 }
02559                 else {
02560                     rb_hash_aset(constant, rb_str_new2(pName), val);
02561                 }
02562                 SysFreeString(bstr);
02563                 if(pName) {
02564                     free(pName);
02565                     pName = NULL;
02566                 }
02567             }
02568             pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
02569         }
02570         pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
02571         OLE_RELEASE(pTypeInfo);
02572     }
02573     rb_define_const(klass, "CONSTANTS", constant);
02574 }
02575 
02576 static HRESULT
02577 clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid)
02578 {
02579     HKEY hlm;
02580     HKEY hpid;
02581     VALUE subkey;
02582     LONG err;
02583     char clsid[100];
02584     OLECHAR *pbuf;
02585     DWORD len;
02586     DWORD dwtype;
02587     HRESULT hr = S_OK;
02588     err = RegConnectRegistry(StringValuePtr(host), HKEY_LOCAL_MACHINE, &hlm);
02589     if (err != ERROR_SUCCESS)
02590         return HRESULT_FROM_WIN32(err);
02591     subkey = rb_str_new2("SOFTWARE\\Classes\\");
02592     rb_str_concat(subkey, com);
02593     rb_str_cat2(subkey, "\\CLSID");
02594     err = RegOpenKeyEx(hlm, StringValuePtr(subkey), 0, KEY_READ, &hpid);
02595     if (err != ERROR_SUCCESS)
02596         hr = HRESULT_FROM_WIN32(err);
02597     else {
02598         len = sizeof(clsid);
02599         err = RegQueryValueEx(hpid, "", NULL, &dwtype, (BYTE *)clsid, &len);
02600         if (err == ERROR_SUCCESS && dwtype == REG_SZ) {
02601             pbuf  = ole_mb2wc(clsid, -1);
02602             hr = CLSIDFromString(pbuf, pclsid);
02603             SysFreeString(pbuf);
02604         }
02605         else {
02606             hr = HRESULT_FROM_WIN32(err);
02607         }
02608         RegCloseKey(hpid);
02609     }
02610     RegCloseKey(hlm);
02611     return hr;
02612 }
02613 
02614 static VALUE
02615 ole_create_dcom(int argc, VALUE *argv, VALUE self)
02616 {
02617     VALUE ole, host, others;
02618     HRESULT hr;
02619     CLSID   clsid;
02620     OLECHAR *pbuf;
02621 
02622     COSERVERINFO serverinfo;
02623     MULTI_QI multi_qi;
02624     DWORD clsctx = CLSCTX_REMOTE_SERVER;
02625 
02626     if (!gole32)
02627         gole32 = LoadLibrary("OLE32");
02628     if (!gole32)
02629         rb_raise(rb_eRuntimeError, "failed to load OLE32");
02630     if (!gCoCreateInstanceEx)
02631         gCoCreateInstanceEx = (FNCOCREATEINSTANCEEX*)
02632             GetProcAddress(gole32, "CoCreateInstanceEx");
02633     if (!gCoCreateInstanceEx)
02634         rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment");
02635     rb_scan_args(argc, argv, "2*", &ole, &host, &others);
02636 
02637     pbuf  = ole_vstr2wc(ole);
02638     hr = CLSIDFromProgID(pbuf, &clsid);
02639     if (FAILED(hr))
02640         hr = clsid_from_remote(host, ole, &clsid);
02641     if (FAILED(hr))
02642         hr = CLSIDFromString(pbuf, &clsid);
02643     SysFreeString(pbuf);
02644     if (FAILED(hr))
02645         ole_raise(hr, eWIN32OLERuntimeError,
02646                   "unknown OLE server: `%s'",
02647                   StringValuePtr(ole));
02648     memset(&serverinfo, 0, sizeof(COSERVERINFO));
02649     serverinfo.pwszName = ole_vstr2wc(host);
02650     memset(&multi_qi, 0, sizeof(MULTI_QI));
02651     multi_qi.pIID = &IID_IDispatch;
02652     hr = gCoCreateInstanceEx(&clsid, NULL, clsctx, &serverinfo, 1, &multi_qi);
02653     SysFreeString(serverinfo.pwszName);
02654     if (FAILED(hr))
02655         ole_raise(hr, eWIN32OLERuntimeError,
02656                   "failed to create DCOM server `%s' in `%s'",
02657                   StringValuePtr(ole),
02658                   StringValuePtr(host));
02659 
02660     ole_set_member(self, (IDispatch*)multi_qi.pItf);
02661     return self;
02662 }
02663 
02664 static VALUE
02665 ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self)
02666 {
02667     IBindCtx *pBindCtx;
02668     IMoniker *pMoniker;
02669     IDispatch *pDispatch;
02670     void *p;
02671     HRESULT hr;
02672     OLECHAR *pbuf;
02673     ULONG eaten = 0;
02674 
02675     ole_initialize();
02676 
02677     hr = CreateBindCtx(0, &pBindCtx);
02678     if(FAILED(hr)) {
02679         ole_raise(hr, eWIN32OLERuntimeError,
02680                   "failed to create bind context");
02681     }
02682 
02683     pbuf  = ole_vstr2wc(moniker);
02684     hr = MkParseDisplayName(pBindCtx, pbuf, &eaten, &pMoniker);
02685     SysFreeString(pbuf);
02686     if(FAILED(hr)) {
02687         OLE_RELEASE(pBindCtx);
02688         ole_raise(hr, eWIN32OLERuntimeError,
02689                   "failed to parse display name of moniker `%s'",
02690                   StringValuePtr(moniker));
02691     }
02692     hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL,
02693                                         &IID_IDispatch, &p);
02694     pDispatch = p;
02695     OLE_RELEASE(pMoniker);
02696     OLE_RELEASE(pBindCtx);
02697 
02698     if(FAILED(hr)) {
02699         ole_raise(hr, eWIN32OLERuntimeError,
02700                   "failed to bind moniker `%s'",
02701                   StringValuePtr(moniker));
02702     }
02703     return create_win32ole_object(self, pDispatch, argc, argv);
02704 }
02705 
02706 /*
02707  *  call-seq:
02708  *     WIN32OLE.connect( ole ) --> aWIN32OLE
02709  *
02710  *  Returns running OLE Automation object or WIN32OLE object from moniker.
02711  *  1st argument should be OLE program id or class id or moniker.
02712  *
02713  *     WIN32OLE.connect('Excel.Application') # => WIN32OLE object which represents running Excel.
02714  */
02715 static VALUE
02716 fole_s_connect(int argc, VALUE *argv, VALUE self)
02717 {
02718     VALUE svr_name;
02719     VALUE others;
02720     HRESULT hr;
02721     CLSID   clsid;
02722     OLECHAR *pBuf;
02723     IDispatch *pDispatch;
02724     void *p;
02725     IUnknown *pUnknown;
02726 
02727     rb_secure(4);
02728     /* initialize to use OLE */
02729     ole_initialize();
02730 
02731     rb_scan_args(argc, argv, "1*", &svr_name, &others);
02732     SafeStringValue(svr_name);
02733     if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
02734         rb_raise(rb_eSecurityError, "Insecure Object Connection - %s",
02735                  StringValuePtr(svr_name));
02736     }
02737 
02738     /* get CLSID from OLE server name */
02739     pBuf = ole_vstr2wc(svr_name);
02740     hr = CLSIDFromProgID(pBuf, &clsid);
02741     if(FAILED(hr)) {
02742         hr = CLSIDFromString(pBuf, &clsid);
02743     }
02744     SysFreeString(pBuf);
02745     if(FAILED(hr)) {
02746         return ole_bind_obj(svr_name, argc, argv, self);
02747     }
02748 
02749     hr = GetActiveObject(&clsid, 0, &pUnknown);
02750     if (FAILED(hr)) {
02751         ole_raise(hr, eWIN32OLERuntimeError,
02752                   "OLE server `%s' not running", StringValuePtr(svr_name));
02753     }
02754     hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch, &p);
02755     pDispatch = p;
02756     if(FAILED(hr)) {
02757         OLE_RELEASE(pUnknown);
02758         ole_raise(hr, eWIN32OLERuntimeError,
02759                   "failed to create WIN32OLE server `%s'",
02760                   StringValuePtr(svr_name));
02761     }
02762 
02763     OLE_RELEASE(pUnknown);
02764 
02765     return create_win32ole_object(self, pDispatch, argc, argv);
02766 }
02767 
02768 /*
02769  *  call-seq:
02770  *     WIN32OLE.const_load( ole, mod = WIN32OLE)
02771  *
02772  *  Defines the constants of OLE Automation server as mod's constants.
02773  *  The first argument is WIN32OLE object or type library name.
02774  *  If 2nd argument is omitted, the default is WIN32OLE.
02775  *  The first letter of Ruby's constant variable name is upper case,
02776  *  so constant variable name of WIN32OLE object is capitalized.
02777  *  For example, the 'xlTop' constant of Excel is changed to 'XlTop'
02778  *  in WIN32OLE.
02779  *  If the first letter of constant variabl is not [A-Z], then
02780  *  the constant is defined as CONSTANTS hash element.
02781  *
02782  *     module EXCEL_CONST
02783  *     end
02784  *     excel = WIN32OLE.new('Excel.Application')
02785  *     WIN32OLE.const_load(excel, EXCEL_CONST)
02786  *     puts EXCEL_CONST::XlTop # => -4160
02787  *     puts EXCEL_CONST::CONSTANTS['_xlDialogChartSourceData'] # => 541
02788  *
02789  *     WIN32OLE.const_load(excel)
02790  *     puts WIN32OLE::XlTop # => -4160
02791  *
02792  *     module MSO
02793  *     end
02794  *     WIN32OLE.const_load('Microsoft Office 9.0 Object Library', MSO)
02795  *     puts MSO::MsoLineSingle # => 1
02796  */
02797 static VALUE
02798 fole_s_const_load(int argc, VALUE *argv, VALUE self)
02799 {
02800     VALUE ole;
02801     VALUE klass;
02802     struct oledata *pole;
02803     ITypeInfo *pTypeInfo;
02804     ITypeLib *pTypeLib;
02805     unsigned int index;
02806     HRESULT hr;
02807     OLECHAR *pBuf;
02808     VALUE file;
02809     LCID    lcid = cWIN32OLE_lcid;
02810 
02811     rb_secure(4);
02812     rb_scan_args(argc, argv, "11", &ole, &klass);
02813     if (TYPE(klass) != T_CLASS &&
02814         TYPE(klass) != T_MODULE &&
02815         TYPE(klass) != T_NIL) {
02816         rb_raise(rb_eTypeError, "2nd parameter must be Class or Module");
02817     }
02818     if (rb_obj_is_kind_of(ole, cWIN32OLE)) {
02819         OLEData_Get_Struct(ole, pole);
02820         hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
02821                                                   0, lcid, &pTypeInfo);
02822         if(FAILED(hr)) {
02823             ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
02824         }
02825         hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
02826         if(FAILED(hr)) {
02827             OLE_RELEASE(pTypeInfo);
02828             ole_raise(hr, rb_eRuntimeError, "failed to GetContainingTypeLib");
02829         }
02830         OLE_RELEASE(pTypeInfo);
02831         if(TYPE(klass) != T_NIL) {
02832             ole_const_load(pTypeLib, klass, self);
02833         }
02834         else {
02835             ole_const_load(pTypeLib, cWIN32OLE, self);
02836         }
02837         OLE_RELEASE(pTypeLib);
02838     }
02839     else if(TYPE(ole) == T_STRING) {
02840         file = typelib_file(ole);
02841         if (file == Qnil) {
02842             file = ole;
02843         }
02844         pBuf = ole_vstr2wc(file);
02845         hr = LoadTypeLibEx(pBuf, REGKIND_NONE, &pTypeLib);
02846         SysFreeString(pBuf);
02847         if (FAILED(hr))
02848           ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx");
02849         if(TYPE(klass) != T_NIL) {
02850             ole_const_load(pTypeLib, klass, self);
02851         }
02852         else {
02853             ole_const_load(pTypeLib, cWIN32OLE, self);
02854         }
02855         OLE_RELEASE(pTypeLib);
02856     }
02857     else {
02858         rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE instance");
02859     }
02860     return Qnil;
02861 }
02862 
02863 static VALUE
02864 ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes)
02865 {
02866 
02867     long count;
02868     int i;
02869     HRESULT hr;
02870     BSTR bstr;
02871     ITypeInfo *pTypeInfo;
02872     VALUE type;
02873 
02874     rb_secure(4);
02875     count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
02876     for (i = 0; i < count; i++) {
02877         hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
02878                                                 &bstr, NULL, NULL, NULL);
02879         if (FAILED(hr))
02880             continue;
02881 
02882         hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
02883         if (FAILED(hr))
02884             continue;
02885 
02886         type = foletype_s_allocate(cWIN32OLE_TYPE);
02887         oletype_set_member(type, pTypeInfo, WC2VSTR(bstr));
02888 
02889         rb_ary_push(classes, type);
02890         OLE_RELEASE(pTypeInfo);
02891     }
02892     return classes;
02893 }
02894 
02895 static ULONG
02896 reference_count(struct oledata * pole)
02897 {
02898     ULONG n = 0;
02899     if(pole->pDispatch) {
02900         OLE_ADDREF(pole->pDispatch);
02901         n = OLE_RELEASE(pole->pDispatch);
02902     }
02903     return n;
02904 }
02905 
02906 /*
02907  *  call-seq:
02908  *     WIN32OLE.ole_reference_count(aWIN32OLE) --> number
02909  *
02910  *  Returns reference counter of Dispatch interface of WIN32OLE object.
02911  *  You should not use this method because this method
02912  *  exists only for debugging WIN32OLE.
02913  */
02914 static VALUE
02915 fole_s_reference_count(VALUE self, VALUE obj)
02916 {
02917     struct oledata * pole;
02918     OLEData_Get_Struct(obj, pole);
02919     return INT2NUM(reference_count(pole));
02920 }
02921 
02922 /*
02923  *  call-seq:
02924  *     WIN32OLE.ole_free(aWIN32OLE) --> number
02925  *
02926  *  Invokes Release method of Dispatch interface of WIN32OLE object.
02927  *  You should not use this method because this method
02928  *  exists only for debugging WIN32OLE.
02929  *  The return value is reference counter of OLE object.
02930  */
02931 static VALUE
02932 fole_s_free(VALUE self, VALUE obj)
02933 {
02934     ULONG n = 0;
02935     struct oledata * pole;
02936     OLEData_Get_Struct(obj, pole);
02937     if(pole->pDispatch) {
02938         if (reference_count(pole) > 0) {
02939             n = OLE_RELEASE(pole->pDispatch);
02940         }
02941     }
02942     return INT2NUM(n);
02943 }
02944 
02945 static HWND
02946 ole_show_help(VALUE helpfile, VALUE helpcontext)
02947 {
02948     FNHTMLHELP *pfnHtmlHelp;
02949     HWND hwnd = 0;
02950 
02951     if(!ghhctrl)
02952         ghhctrl = LoadLibrary("HHCTRL.OCX");
02953     if (!ghhctrl)
02954         return hwnd;
02955     pfnHtmlHelp = (FNHTMLHELP*)GetProcAddress(ghhctrl, "HtmlHelpA");
02956     if (!pfnHtmlHelp)
02957         return hwnd;
02958     hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
02959                     0x0f, NUM2INT(helpcontext));
02960     if (hwnd == 0)
02961         hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
02962                  0,  NUM2INT(helpcontext));
02963     return hwnd;
02964 }
02965 
02966 /*
02967  *  call-seq:
02968  *     WIN32OLE.ole_show_help(obj [,helpcontext])
02969  *
02970  *  Displays helpfile. The 1st argument specifies WIN32OLE_TYPE
02971  *  object or WIN32OLE_METHOD object or helpfile.
02972  *
02973  *     excel = WIN32OLE.new('Excel.Application')
02974  *     typeobj = excel.ole_type
02975  *     WIN32OLE.ole_show_help(typeobj)
02976  */
02977 static VALUE
02978 fole_s_show_help(int argc, VALUE *argv, VALUE self)
02979 {
02980     VALUE target;
02981     VALUE helpcontext;
02982     VALUE helpfile;
02983     VALUE name;
02984     HWND  hwnd;
02985     rb_scan_args(argc, argv, "11", &target, &helpcontext);
02986     if (rb_obj_is_kind_of(target, cWIN32OLE_TYPE) ||
02987         rb_obj_is_kind_of(target, cWIN32OLE_METHOD)) {
02988         helpfile = rb_funcall(target, rb_intern("helpfile"), 0);
02989         if(strlen(StringValuePtr(helpfile)) == 0) {
02990             name = rb_ivar_get(target, rb_intern("name"));
02991             rb_raise(rb_eRuntimeError, "no helpfile of `%s'",
02992                      StringValuePtr(name));
02993         }
02994         helpcontext = rb_funcall(target, rb_intern("helpcontext"), 0);
02995     } else {
02996         helpfile = target;
02997     }
02998     if (TYPE(helpfile) != T_STRING) {
02999         rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD)");
03000     }
03001     hwnd = ole_show_help(helpfile, helpcontext);
03002     if(hwnd == 0) {
03003         rb_raise(rb_eRuntimeError, "failed to open help file `%s'",
03004                  StringValuePtr(helpfile));
03005     }
03006     return Qnil;
03007 }
03008 
03009 /*
03010  *  call-seq:
03011  *     WIN32OLE.codepage
03012  *
03013  *  Returns current codepage.
03014  *     WIN32OLE.codepage # => WIN32OLE::CP_ACP
03015  */
03016 static VALUE
03017 fole_s_get_code_page(VALUE self)
03018 {
03019     return INT2FIX(cWIN32OLE_cp);
03020 }
03021 
03022 static BOOL CALLBACK
03023 installed_code_page_proc(LPTSTR str) {
03024     if (strtoul(str, NULL, 10) == g_cp_to_check) {
03025         g_cp_installed = TRUE;
03026         return FALSE;
03027     }
03028     return TRUE;
03029 }
03030 
03031 static BOOL
03032 code_page_installed(UINT cp)
03033 {
03034     g_cp_installed = FALSE;
03035     g_cp_to_check = cp;
03036     EnumSystemCodePages(installed_code_page_proc, CP_INSTALLED);
03037     return g_cp_installed;
03038 }
03039 
03040 /*
03041  *  call-seq:
03042  *     WIN32OLE.codepage = CP
03043  *
03044  *  Sets current codepage.
03045  *  The WIN32OLE.codepage is initialized according to
03046  *  Encoding.default_internal.
03047  *  If Encoding.default_internal is nil then WIN32OLE.codepage
03048  *  is initialized according to Encoding.default_external.
03049  *
03050  *     WIN32OLE.codepage = WIN32OLE::CP_UTF8
03051  *     WIN32OLE.codepage = 65001
03052  */
03053 static VALUE
03054 fole_s_set_code_page(VALUE self, VALUE vcp)
03055 {
03056     UINT cp = FIX2INT(vcp);
03057     set_ole_codepage(cp);
03058     /*
03059      * Should this method return old codepage?
03060      */
03061     return Qnil;
03062 }
03063 
03064 /*
03065  *  call-seq:
03066  *     WIN32OLE.locale -> locale id.
03067  *
03068  *  Returns current locale id (lcid). The default locale is
03069  *  LOCALE_SYSTEM_DEFAULT.
03070  *
03071  *     lcid = WIN32OLE.locale
03072  */
03073 static VALUE
03074 fole_s_get_locale(VALUE self)
03075 {
03076     return INT2FIX(cWIN32OLE_lcid);
03077 }
03078 
03079 static BOOL
03080 CALLBACK installed_lcid_proc(LPTSTR str)
03081 {
03082     if (strcmp(str, g_lcid_to_check) == 0) {
03083         g_lcid_installed = TRUE;
03084         return FALSE;
03085     }
03086     return TRUE;
03087 }
03088 
03089 static BOOL
03090 lcid_installed(LCID lcid)
03091 {
03092     g_lcid_installed = FALSE;
03093     snprintf(g_lcid_to_check, sizeof(g_lcid_to_check), "%08lx", lcid);
03094     EnumSystemLocales(installed_lcid_proc, LCID_INSTALLED);
03095     return g_lcid_installed;
03096 }
03097 
03098 /*
03099  *  call-seq:
03100  *     WIN32OLE.locale = lcid
03101  *
03102  *  Sets current locale id (lcid).
03103  *
03104  *     WIN32OLE.locale = 1033 # set locale English(U.S)
03105  *     obj = WIN32OLE_VARIANT.new("$100,000", WIN32OLE::VARIANT::VT_CY)
03106  *
03107  */
03108 static VALUE
03109 fole_s_set_locale(VALUE self, VALUE vlcid)
03110 {
03111     LCID lcid = FIX2INT(vlcid);
03112     if (lcid_installed(lcid)) {
03113         cWIN32OLE_lcid = lcid;
03114     } else {
03115         switch (lcid) {
03116         case LOCALE_SYSTEM_DEFAULT:
03117         case LOCALE_USER_DEFAULT:
03118             cWIN32OLE_lcid = lcid;
03119             break;
03120         default:
03121             rb_raise(eWIN32OLERuntimeError, "not installed locale: %u", (unsigned int)lcid);
03122         }
03123     }
03124     return Qnil;
03125 }
03126 
03127 /*
03128  *  call-seq:
03129  *     WIN32OLE.create_guid
03130  *
03131  *  Creates GUID.
03132  *     WIN32OLE.create_guid # => {1CB530F1-F6B1-404D-BCE6-1959BF91F4A8}
03133  */
03134 static VALUE
03135 fole_s_create_guid(VALUE self)
03136 {
03137     GUID guid;
03138     HRESULT hr;
03139     OLECHAR bstr[80];
03140     int len = 0;
03141     hr = CoCreateGuid(&guid);
03142     if (FAILED(hr)) {
03143         ole_raise(hr, eWIN32OLERuntimeError, "failed to create GUID");
03144     }
03145     len = StringFromGUID2(&guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
03146     if (len == 0) {
03147         rb_raise(rb_eRuntimeError, "failed to create GUID(buffer over)");
03148     }
03149     return ole_wc2vstr(bstr, FALSE);
03150 }
03151 
03152 /*
03153  * WIN32OLE.ole_initialize and WIN32OLE.ole_uninitialize
03154  * are used in win32ole.rb to fix the issue bug #2618 (ruby-core:27634).
03155  * You must not use thease method.
03156  */
03157 
03158 /* :nodoc */
03159 static VALUE
03160 fole_s_ole_initialize(VALUE self)
03161 {
03162     ole_initialize();
03163     return Qnil;
03164 }
03165 
03166 /* :nodoc */
03167 static VALUE
03168 fole_s_ole_uninitialize(VALUE self)
03169 {
03170     ole_uninitialize();
03171     return Qnil;
03172 }
03173 
03174 /*
03175  * Document-class: WIN32OLE
03176  *
03177  *   <code>WIN32OLE</code> objects represent OLE Automation object in Ruby.
03178  *
03179  *   By using WIN32OLE, you can access OLE server like VBScript.
03180  *
03181  *   Here is sample script.
03182  *
03183  *     require 'win32ole'
03184  *
03185  *     excel = WIN32OLE.new('Excel.Application')
03186  *     excel.visible = true
03187  *     workbook = excel.Workbooks.Add();
03188  *     worksheet = workbook.Worksheets(1);
03189  *     worksheet.Range("A1:D1").value = ["North","South","East","West"];
03190  *     worksheet.Range("A2:B2").value = [5.2, 10];
03191  *     worksheet.Range("C2").value = 8;
03192  *     worksheet.Range("D2").value = 20;
03193  *
03194  *     range = worksheet.Range("A1:D2");
03195  *     range.select
03196  *     chart = workbook.Charts.Add;
03197  *
03198  *     workbook.saved = true;
03199  *
03200  *     excel.ActiveWorkbook.Close(0);
03201  *     excel.Quit();
03202  *
03203  *  Unfortunately, Win32OLE doesn't support the argument passed by
03204  *  reference directly.
03205  *  Instead, Win32OLE provides WIN32OLE::ARGV.
03206  *  If you want to get the result value of argument passed by reference,
03207  *  you can use WIN32OLE::ARGV.
03208  *
03209  *     oleobj.method(arg1, arg2, refargv3)
03210  *     puts WIN32OLE::ARGV[2]   # the value of refargv3 after called oleobj.method
03211  *
03212  */
03213 
03214 /*
03215  *  call-seq:
03216  *     WIN32OLE.new(server, [host]) -> WIN32OLE object
03217  *
03218  *  Returns a new WIN32OLE object(OLE Automation object).
03219  *  The first argument server specifies OLE Automation server.
03220  *  The first argument should be CLSID or PROGID.
03221  *  If second argument host specified, then returns OLE Automation
03222  *  object on host.
03223  *
03224  *      WIN32OLE.new('Excel.Application') # => Excel OLE Automation WIN32OLE object.
03225  *      WIN32OLE.new('{00024500-0000-0000-C000-000000000046}') # => Excel OLE Automation WIN32OLE object.
03226  */
03227 static VALUE
03228 fole_initialize(int argc, VALUE *argv, VALUE self)
03229 {
03230     VALUE svr_name;
03231     VALUE host;
03232     VALUE others;
03233     HRESULT hr;
03234     CLSID   clsid;
03235     OLECHAR *pBuf;
03236     IDispatch *pDispatch;
03237     void *p;
03238     rb_secure(4);
03239     rb_call_super(0, 0);
03240     rb_scan_args(argc, argv, "11*", &svr_name, &host, &others);
03241 
03242     SafeStringValue(svr_name);
03243     if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
03244         rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
03245                  StringValuePtr(svr_name));
03246     }
03247     if (!NIL_P(host)) {
03248         SafeStringValue(host);
03249         if (rb_safe_level() > 0 && OBJ_TAINTED(host)) {
03250             rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
03251                      StringValuePtr(svr_name));
03252         }
03253         return ole_create_dcom(argc, argv, self);
03254     }
03255 
03256     /* get CLSID from OLE server name */
03257     pBuf  = ole_vstr2wc(svr_name);
03258     hr = CLSIDFromProgID(pBuf, &clsid);
03259     if(FAILED(hr)) {
03260         hr = CLSIDFromString(pBuf, &clsid);
03261     }
03262     SysFreeString(pBuf);
03263     if(FAILED(hr)) {
03264         ole_raise(hr, eWIN32OLERuntimeError,
03265                   "unknown OLE server: `%s'",
03266                   StringValuePtr(svr_name));
03267     }
03268 
03269     /* get IDispatch interface */
03270     hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
03271                           &IID_IDispatch, &p);
03272     pDispatch = p;
03273     if(FAILED(hr)) {
03274         ole_raise(hr, eWIN32OLERuntimeError,
03275                   "failed to create WIN32OLE object from `%s'",
03276                   StringValuePtr(svr_name));
03277     }
03278 
03279     ole_set_member(self, pDispatch);
03280     return self;
03281 }
03282 
03283 static VALUE
03284 hash2named_arg(VALUE pair, struct oleparam* pOp)
03285 {
03286     unsigned int index, i;
03287     VALUE key, value;
03288     index = pOp->dp.cNamedArgs;
03289 
03290     /*---------------------------------------------
03291       the data-type of key must be String or Symbol
03292     -----------------------------------------------*/
03293     key = rb_ary_entry(pair, 0);
03294     if(TYPE(key) != T_STRING && TYPE(key) != T_SYMBOL) {
03295         /* clear name of dispatch parameters */
03296         for(i = 1; i < index + 1; i++) {
03297             SysFreeString(pOp->pNamedArgs[i]);
03298         }
03299         /* clear dispatch parameters */
03300         for(i = 0; i < index; i++ ) {
03301             VariantClear(&(pOp->dp.rgvarg[i]));
03302         }
03303         /* raise an exception */
03304         rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
03305     }
03306     if (TYPE(key) == T_SYMBOL) {
03307         key = rb_sym_to_s(key);
03308     }
03309 
03310     /* pNamedArgs[0] is <method name>, so "index + 1" */
03311     pOp->pNamedArgs[index + 1] = ole_vstr2wc(key);
03312 
03313     value = rb_ary_entry(pair, 1);
03314     VariantInit(&(pOp->dp.rgvarg[index]));
03315     ole_val2variant(value, &(pOp->dp.rgvarg[index]));
03316 
03317     pOp->dp.cNamedArgs += 1;
03318     return Qnil;
03319 }
03320 
03321 static VALUE
03322 set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end)
03323 {
03324     VALUE argv = rb_const_get(cWIN32OLE, rb_intern("ARGV"));
03325 
03326     Check_Type(argv, T_ARRAY);
03327     rb_ary_clear(argv);
03328     while (end-- > beg) {
03329         rb_ary_push(argv, ole_variant2val(&realargs[end]));
03330         VariantClear(&realargs[end]);
03331     }
03332     return argv;
03333 }
03334 
03335 static VALUE
03336 ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket)
03337 {
03338     LCID    lcid = cWIN32OLE_lcid;
03339     struct oledata *pole;
03340     HRESULT hr;
03341     VALUE cmd;
03342     VALUE paramS;
03343     VALUE param;
03344     VALUE obj;
03345     VALUE v;
03346 
03347     BSTR wcmdname;
03348 
03349     DISPID DispID;
03350     DISPID* pDispID;
03351     EXCEPINFO excepinfo;
03352     VARIANT result;
03353     VARIANTARG* realargs = NULL;
03354     unsigned int argErr = 0;
03355     unsigned int i;
03356     unsigned int cNamedArgs;
03357     int n;
03358     struct oleparam op;
03359     struct olevariantdata *pvar;
03360     memset(&excepinfo, 0, sizeof(EXCEPINFO));
03361 
03362     VariantInit(&result);
03363 
03364     op.dp.rgvarg = NULL;
03365     op.dp.rgdispidNamedArgs = NULL;
03366     op.dp.cNamedArgs = 0;
03367     op.dp.cArgs = 0;
03368 
03369     rb_scan_args(argc, argv, "1*", &cmd, &paramS);
03370     if(TYPE(cmd) != T_STRING && TYPE(cmd) != T_SYMBOL && !is_bracket) {
03371         rb_raise(rb_eTypeError, "method is wrong type (expected String or Symbol)");
03372     }
03373     if (TYPE(cmd) == T_SYMBOL) {
03374         cmd = rb_sym_to_s(cmd);
03375     }
03376     OLEData_Get_Struct(self, pole);
03377     if(!pole->pDispatch) {
03378         rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
03379     }
03380     if (is_bracket) {
03381         DispID = DISPID_VALUE;
03382         argc += 1;
03383         rb_ary_unshift(paramS, cmd);
03384     } else {
03385         wcmdname = ole_vstr2wc(cmd);
03386         hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
03387                 &wcmdname, 1, lcid, &DispID);
03388         SysFreeString(wcmdname);
03389         if(FAILED(hr)) {
03390             ole_raise(hr, rb_eNoMethodError,
03391                     "unknown property or method: `%s'",
03392                     StringValuePtr(cmd));
03393         }
03394     }
03395 
03396     /* pick up last argument of method */
03397     param = rb_ary_entry(paramS, argc-2);
03398 
03399     op.dp.cNamedArgs = 0;
03400 
03401     /* if last arg is hash object */
03402     if(TYPE(param) == T_HASH) {
03403         /*------------------------------------------
03404           hash object ==> named dispatch parameters
03405         --------------------------------------------*/
03406         cNamedArgs = NUM2INT(rb_funcall(param, rb_intern("length"), 0));
03407         op.dp.cArgs = cNamedArgs + argc - 2;
03408         op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
03409         op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
03410         rb_block_call(param, rb_intern("each"), 0, 0, hash2named_arg, (VALUE)&op);
03411 
03412         pDispID = ALLOCA_N(DISPID, cNamedArgs + 1);
03413         op.pNamedArgs[0] = ole_vstr2wc(cmd);
03414         hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch,
03415                                                     &IID_NULL,
03416                                                     op.pNamedArgs,
03417                                                     op.dp.cNamedArgs + 1,
03418                                                     lcid, pDispID);
03419         for(i = 0; i < op.dp.cNamedArgs + 1; i++) {
03420             SysFreeString(op.pNamedArgs[i]);
03421             op.pNamedArgs[i] = NULL;
03422         }
03423         if(FAILED(hr)) {
03424             /* clear dispatch parameters */
03425             for(i = 0; i < op.dp.cArgs; i++ ) {
03426                 VariantClear(&op.dp.rgvarg[i]);
03427             }
03428             ole_raise(hr, eWIN32OLERuntimeError,
03429                       "failed to get named argument info: `%s'",
03430                       StringValuePtr(cmd));
03431         }
03432         op.dp.rgdispidNamedArgs = &(pDispID[1]);
03433     }
03434     else {
03435         cNamedArgs = 0;
03436         op.dp.cArgs = argc - 1;
03437         op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
03438         if (op.dp.cArgs > 0) {
03439             op.dp.rgvarg  = ALLOCA_N(VARIANTARG, op.dp.cArgs);
03440         }
03441     }
03442     /*--------------------------------------
03443       non hash args ==> dispatch parameters
03444      ----------------------------------------*/
03445     if(op.dp.cArgs > cNamedArgs) {
03446         realargs = ALLOCA_N(VARIANTARG, op.dp.cArgs-cNamedArgs+1);
03447         for(i = cNamedArgs; i < op.dp.cArgs; i++) {
03448             n = op.dp.cArgs - i + cNamedArgs - 1;
03449             VariantInit(&realargs[n]);
03450             VariantInit(&op.dp.rgvarg[n]);
03451             param = rb_ary_entry(paramS, i-cNamedArgs);
03452             if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
03453                 Data_Get_Struct(param, struct olevariantdata, pvar);
03454                 VariantCopy(&op.dp.rgvarg[n], &(pvar->var));
03455             } else {
03456                 ole_val2variant(param, &realargs[n]);
03457                 V_VT(&op.dp.rgvarg[n]) = VT_VARIANT | VT_BYREF;
03458                 V_VARIANTREF(&op.dp.rgvarg[n]) = &realargs[n];
03459             }
03460         }
03461     }
03462     /* apparent you need to call propput, you need this */
03463     if (wFlags & DISPATCH_PROPERTYPUT) {
03464         if (op.dp.cArgs == 0)
03465             ole_raise(ResultFromScode(E_INVALIDARG), eWIN32OLERuntimeError, "argument error");
03466 
03467         op.dp.cNamedArgs = 1;
03468         op.dp.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
03469         op.dp.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
03470     }
03471 
03472     hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
03473                                          &IID_NULL, lcid, wFlags, &op.dp,
03474                                          &result, &excepinfo, &argErr);
03475 
03476     if (FAILED(hr)) {
03477         /* retry to call args by value */
03478         if(op.dp.cArgs >= cNamedArgs) {
03479             for(i = cNamedArgs; i < op.dp.cArgs; i++) {
03480                 n = op.dp.cArgs - i + cNamedArgs - 1;
03481                 param = rb_ary_entry(paramS, i-cNamedArgs);
03482                 ole_val2variant(param, &op.dp.rgvarg[n]);
03483             }
03484             if (hr == DISP_E_EXCEPTION) {
03485                 ole_freeexceptinfo(&excepinfo);
03486             }
03487             memset(&excepinfo, 0, sizeof(EXCEPINFO));
03488             VariantInit(&result);
03489             hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
03490                                                  &IID_NULL, lcid, wFlags,
03491                                                  &op.dp, &result,
03492                                                  &excepinfo, &argErr);
03493 
03494             /* mega kludge. if a method in WORD is called and we ask
03495              * for a result when one is not returned then
03496              * hResult == DISP_E_EXCEPTION. this only happens on
03497              * functions whose DISPID > 0x8000 */
03498             if ((hr == DISP_E_EXCEPTION || hr == DISP_E_MEMBERNOTFOUND) && DispID > 0x8000) {
03499                 if (hr == DISP_E_EXCEPTION) {
03500                     ole_freeexceptinfo(&excepinfo);
03501                 }
03502                 memset(&excepinfo, 0, sizeof(EXCEPINFO));
03503                 hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
03504                         &IID_NULL, lcid, wFlags,
03505                         &op.dp, NULL,
03506                         &excepinfo, &argErr);
03507 
03508             }
03509             for(i = cNamedArgs; i < op.dp.cArgs; i++) {
03510                 n = op.dp.cArgs - i + cNamedArgs - 1;
03511                 VariantClear(&op.dp.rgvarg[n]);
03512             }
03513         }
03514 
03515         if (FAILED(hr)) {
03516             /* retry after converting nil to VT_EMPTY */
03517             if (op.dp.cArgs > cNamedArgs) {
03518                 for(i = cNamedArgs; i < op.dp.cArgs; i++) {
03519                     n = op.dp.cArgs - i + cNamedArgs - 1;
03520                     param = rb_ary_entry(paramS, i-cNamedArgs);
03521                     ole_val2variant2(param, &op.dp.rgvarg[n]);
03522                 }
03523                 if (hr == DISP_E_EXCEPTION) {
03524                     ole_freeexceptinfo(&excepinfo);
03525                 }
03526                 memset(&excepinfo, 0, sizeof(EXCEPINFO));
03527                 VariantInit(&result);
03528                 hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
03529                         &IID_NULL, lcid, wFlags,
03530                         &op.dp, &result,
03531                         &excepinfo, &argErr);
03532                 for(i = cNamedArgs; i < op.dp.cArgs; i++) {
03533                     n = op.dp.cArgs - i + cNamedArgs - 1;
03534                     VariantClear(&op.dp.rgvarg[n]);
03535                 }
03536             }
03537         }
03538 
03539     }
03540     /* clear dispatch parameter */
03541     if(op.dp.cArgs > cNamedArgs) {
03542         for(i = cNamedArgs; i < op.dp.cArgs; i++) {
03543             n = op.dp.cArgs - i + cNamedArgs - 1;
03544             param = rb_ary_entry(paramS, i-cNamedArgs);
03545             if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
03546                 ole_val2variant(param, &realargs[n]);
03547             }
03548         }
03549         set_argv(realargs, cNamedArgs, op.dp.cArgs);
03550     }
03551     else {
03552         for(i = 0; i < op.dp.cArgs; i++) {
03553             VariantClear(&op.dp.rgvarg[i]);
03554         }
03555     }
03556 
03557     if (FAILED(hr)) {
03558         v = ole_excepinfo2msg(&excepinfo);
03559         ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `%s': )%s",
03560                   StringValuePtr(cmd),
03561                   StringValuePtr(v));
03562     }
03563     obj = ole_variant2val(&result);
03564     VariantClear(&result);
03565     return obj;
03566 }
03567 
03568 /*
03569  *  call-seq:
03570  *     WIN32OLE#invoke(method, [arg1,...])  => return value of method.
03571  *
03572  *  Runs OLE method.
03573  *  The first argument specifies the method name of OLE Automation object.
03574  *  The others specify argument of the <i>method</i>.
03575  *  If you can not execute <i>method</i> directly, then use this method instead.
03576  *
03577  *    excel = WIN32OLE.new('Excel.Application')
03578  *    excel.invoke('Quit')  # => same as excel.Quit
03579  *
03580  */
03581 static VALUE
03582 fole_invoke(int argc, VALUE *argv, VALUE self)
03583 {
03584     return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
03585 }
03586 
03587 static VALUE
03588 ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind)
03589 {
03590     HRESULT hr;
03591     struct oledata *pole;
03592     unsigned int argErr = 0;
03593     EXCEPINFO excepinfo;
03594     VARIANT result;
03595     DISPPARAMS dispParams;
03596     VARIANTARG* realargs = NULL;
03597     int i, j;
03598     VALUE obj = Qnil;
03599     VALUE tp, param;
03600     VALUE v;
03601     VARTYPE vt;
03602 
03603     Check_Type(args, T_ARRAY);
03604     Check_Type(types, T_ARRAY);
03605 
03606     memset(&excepinfo, 0, sizeof(EXCEPINFO));
03607     memset(&dispParams, 0, sizeof(DISPPARAMS));
03608     VariantInit(&result);
03609     OLEData_Get_Struct(self, pole);
03610 
03611     dispParams.cArgs = RARRAY_LEN(args);
03612     dispParams.rgvarg = ALLOCA_N(VARIANTARG, dispParams.cArgs);
03613     realargs = ALLOCA_N(VARIANTARG, dispParams.cArgs);
03614     for (i = 0, j = dispParams.cArgs - 1; i < (int)dispParams.cArgs; i++, j--)
03615     {
03616         VariantInit(&realargs[i]);
03617         VariantInit(&dispParams.rgvarg[i]);
03618         tp = rb_ary_entry(types, j);
03619         vt = (VARTYPE)FIX2INT(tp);
03620         V_VT(&dispParams.rgvarg[i]) = vt;
03621         param = rb_ary_entry(args, j);
03622         if (param == Qnil)
03623         {
03624 
03625             V_VT(&dispParams.rgvarg[i]) = V_VT(&realargs[i]) = VT_ERROR;
03626             V_ERROR(&dispParams.rgvarg[i]) = V_ERROR(&realargs[i]) = DISP_E_PARAMNOTFOUND;
03627         }
03628         else
03629         {
03630             if (vt & VT_ARRAY)
03631             {
03632                 int ent;
03633                 LPBYTE pb;
03634                 short* ps;
03635                 LPLONG pl;
03636                 VARIANT* pv;
03637                 CY *py;
03638                 VARTYPE v;
03639                 SAFEARRAYBOUND rgsabound[1];
03640                 Check_Type(param, T_ARRAY);
03641                 rgsabound[0].lLbound = 0;
03642                 rgsabound[0].cElements = RARRAY_LEN(param);
03643                 v = vt & ~(VT_ARRAY | VT_BYREF);
03644                 V_ARRAY(&realargs[i]) = SafeArrayCreate(v, 1, rgsabound);
03645                 V_VT(&realargs[i]) = VT_ARRAY | v;
03646                 SafeArrayLock(V_ARRAY(&realargs[i]));
03647                 pb = V_ARRAY(&realargs[i])->pvData;
03648                 ps = V_ARRAY(&realargs[i])->pvData;
03649                 pl = V_ARRAY(&realargs[i])->pvData;
03650                 py = V_ARRAY(&realargs[i])->pvData;
03651                 pv = V_ARRAY(&realargs[i])->pvData;
03652                 for (ent = 0; ent < (int)rgsabound[0].cElements; ent++)
03653                 {
03654                     VARIANT velem;
03655                     VALUE elem = rb_ary_entry(param, ent);
03656                     ole_val2variant(elem, &velem);
03657                     if (v != VT_VARIANT)
03658                     {
03659                         VariantChangeTypeEx(&velem, &velem,
03660                             cWIN32OLE_lcid, 0, v);
03661                     }
03662                     switch (v)
03663                     {
03664                     /* 128 bits */
03665                     case VT_VARIANT:
03666                         *pv++ = velem;
03667                         break;
03668                     /* 64 bits */
03669                     case VT_R8:
03670                     case VT_CY:
03671                     case VT_DATE:
03672                         *py++ = V_CY(&velem);
03673                         break;
03674                     /* 16 bits */
03675                     case VT_BOOL:
03676                     case VT_I2:
03677                     case VT_UI2:
03678                         *ps++ = V_I2(&velem);
03679                         break;
03680                     /* 8 bites */
03681                     case VT_UI1:
03682                     case VT_I1:
03683                         *pb++ = V_UI1(&velem);
03684                         break;
03685                     /* 32 bits */
03686                     default:
03687                         *pl++ = V_I4(&velem);
03688                         break;
03689                     }
03690                 }
03691                 SafeArrayUnlock(V_ARRAY(&realargs[i]));
03692             }
03693             else
03694             {
03695                 ole_val2variant(param, &realargs[i]);
03696                 if ((vt & (~VT_BYREF)) != VT_VARIANT)
03697                 {
03698                     hr = VariantChangeTypeEx(&realargs[i], &realargs[i],
03699                                              cWIN32OLE_lcid, 0,
03700                                              (VARTYPE)(vt & (~VT_BYREF)));
03701                     if (hr != S_OK)
03702                     {
03703                         rb_raise(rb_eTypeError, "not valid value");
03704                     }
03705                 }
03706             }
03707             if ((vt & VT_BYREF) || vt == VT_VARIANT)
03708             {
03709                 if (vt == VT_VARIANT)
03710                     V_VT(&dispParams.rgvarg[i]) = VT_VARIANT | VT_BYREF;
03711                 switch (vt & (~VT_BYREF))
03712                 {
03713                 /* 128 bits */
03714                 case VT_VARIANT:
03715                     V_VARIANTREF(&dispParams.rgvarg[i]) = &realargs[i];
03716                     break;
03717                 /* 64 bits */
03718                 case VT_R8:
03719                 case VT_CY:
03720                 case VT_DATE:
03721                     V_CYREF(&dispParams.rgvarg[i]) = &V_CY(&realargs[i]);
03722                     break;
03723                 /* 16 bits */
03724                 case VT_BOOL:
03725                 case VT_I2:
03726                 case VT_UI2:
03727                     V_I2REF(&dispParams.rgvarg[i]) = &V_I2(&realargs[i]);
03728                     break;
03729                 /* 8 bites */
03730                 case VT_UI1:
03731                 case VT_I1:
03732                     V_UI1REF(&dispParams.rgvarg[i]) = &V_UI1(&realargs[i]);
03733                     break;
03734                 /* 32 bits */
03735                 default:
03736                     V_I4REF(&dispParams.rgvarg[i]) = &V_I4(&realargs[i]);
03737                     break;
03738                 }
03739             }
03740             else
03741             {
03742                 /* copy 64 bits of data */
03743                 V_CY(&dispParams.rgvarg[i]) = V_CY(&realargs[i]);
03744             }
03745         }
03746     }
03747 
03748     if (dispkind & DISPATCH_PROPERTYPUT) {
03749         dispParams.cNamedArgs = 1;
03750         dispParams.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
03751         dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
03752     }
03753 
03754     hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, NUM2INT(dispid),
03755                                          &IID_NULL, cWIN32OLE_lcid,
03756                                          dispkind,
03757                                          &dispParams, &result,
03758                                          &excepinfo, &argErr);
03759 
03760     if (FAILED(hr)) {
03761         v = ole_excepinfo2msg(&excepinfo);
03762         ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `<dispatch id:%d>': )%s",
03763                   NUM2INT(dispid),
03764                   StringValuePtr(v));
03765     }
03766 
03767     /* clear dispatch parameter */
03768     if(dispParams.cArgs > 0) {
03769         set_argv(realargs, 0, dispParams.cArgs);
03770     }
03771 
03772     obj = ole_variant2val(&result);
03773     VariantClear(&result);
03774     return obj;
03775 }
03776 
03777 /*
03778  *   call-seq:
03779  *      WIN32OLE#_invoke(dispid, args, types)
03780  *
03781  *   Runs the early binding method.
03782  *   The 1st argument specifies dispatch ID,
03783  *   the 2nd argument specifies the array of arguments,
03784  *   the 3rd argument specifies the array of the type of arguments.
03785  *
03786  *      excel = WIN32OLE.new('Excel.Application')
03787  *      excel._invoke(302, [], []) #  same effect as excel.Quit
03788  */
03789 static VALUE
03790 fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types)
03791 {
03792     return ole_invoke2(self, dispid, args, types, DISPATCH_METHOD);
03793 }
03794 
03795 /*
03796  *  call-seq:
03797  *     WIN32OLE#_getproperty(dispid, args, types)
03798  *
03799  *  Runs the early binding method to get property.
03800  *  The 1st argument specifies dispatch ID,
03801  *  the 2nd argument specifies the array of arguments,
03802  *  the 3rd argument specifies the array of the type of arguments.
03803  *
03804  *     excel = WIN32OLE.new('Excel.Application')
03805  *     puts excel._getproperty(558, [], []) # same effect as puts excel.visible
03806  */
03807 static VALUE
03808 fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
03809 {
03810     return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYGET);
03811 }
03812 
03813 /*
03814  *   call-seq:
03815  *      WIN32OLE#_setproperty(dispid, args, types)
03816  *
03817  *   Runs the early binding method to set property.
03818  *   The 1st argument specifies dispatch ID,
03819  *   the 2nd argument specifies the array of arguments,
03820  *   the 3rd argument specifies the array of the type of arguments.
03821  *
03822  *      excel = WIN32OLE.new('Excel.Application')
03823  *      excel._setproperty(558, [true], [WIN32OLE::VARIANT::VT_BOOL]) # same effect as excel.visible = true
03824  */
03825 static VALUE
03826 fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
03827 {
03828     return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYPUT);
03829 }
03830 
03831 /*
03832  *  call-seq:
03833  *     WIN32OLE[a1, a2, ...]=val
03834  *
03835  *  Sets the value to WIN32OLE object specified by a1, a2, ...
03836  *
03837  *     dict = WIN32OLE.new('Scripting.Dictionary')
03838  *     dict.add('ruby', 'RUBY')
03839  *     dict['ruby'] = 'Ruby'
03840  *     puts dict['ruby'] # => 'Ruby'
03841  *
03842  *  Remark: You can not use this method to set the property value.
03843  *
03844  *     excel = WIN32OLE.new('Excel.Application')
03845  *     # excel['Visible'] = true # This is error !!!
03846  *     excel.Visible = true # You should to use this style to set the property.
03847  *
03848  */
03849 static VALUE
03850 fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self)
03851 {
03852     return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, TRUE);
03853 }
03854 
03855 /*
03856  *  call-seq:
03857  *     WIN32OLE.setproperty('property', [arg1, arg2,...] val)
03858  *
03859  *  Sets property of OLE object.
03860  *  When you want to set property with argument, you can use this method.
03861  *
03862  *     excel = WIN32OLE.new('Excel.Application')
03863  *     excel.Visible = true
03864  *     book = excel.workbooks.add
03865  *     sheet = book.worksheets(1)
03866  *     sheet.setproperty('Cells', 1, 2, 10) # => The B1 cell value is 10.
03867  */
03868 static VALUE
03869 fole_setproperty(int argc, VALUE *argv, VALUE self)
03870 {
03871     return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, FALSE);
03872 }
03873 
03874 /*
03875  *  call-seq:
03876  *     WIN32OLE[a1,a2,...]
03877  *
03878  *  Returns the value of Collection specified by a1, a2,....
03879  *
03880  *     dict = WIN32OLE.new('Scripting.Dictionary')
03881  *     dict.add('ruby', 'Ruby')
03882  *     puts dict['ruby'] # => 'Ruby' (same as `puts dict.item('ruby')')
03883  *
03884  *  Remark: You can not use this method to get the property.
03885  *     excel = WIN32OLE.new('Excel.Application')
03886  *     # puts excel['Visible']  This is error !!!
03887  *     puts excel.Visible # You should to use this style to get the property.
03888  *
03889  */
03890 static VALUE
03891 fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self)
03892 {
03893     return ole_invoke(argc, argv, self, DISPATCH_PROPERTYGET, TRUE);
03894 }
03895 
03896 static VALUE
03897 ole_propertyput(VALUE self, VALUE property, VALUE value)
03898 {
03899     struct oledata *pole;
03900     unsigned argErr;
03901     unsigned int index;
03902     HRESULT hr;
03903     EXCEPINFO excepinfo;
03904     DISPID dispID = DISPID_VALUE;
03905     DISPID dispIDParam = DISPID_PROPERTYPUT;
03906     USHORT wFlags = DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF;
03907     DISPPARAMS dispParams;
03908     VARIANTARG propertyValue[2];
03909     OLECHAR* pBuf[1];
03910     VALUE v;
03911     LCID    lcid = cWIN32OLE_lcid;
03912     dispParams.rgdispidNamedArgs = &dispIDParam;
03913     dispParams.rgvarg = propertyValue;
03914     dispParams.cNamedArgs = 1;
03915     dispParams.cArgs = 1;
03916 
03917     VariantInit(&propertyValue[0]);
03918     VariantInit(&propertyValue[1]);
03919     memset(&excepinfo, 0, sizeof(excepinfo));
03920 
03921     OLEData_Get_Struct(self, pole);
03922 
03923     /* get ID from property name */
03924     pBuf[0]  = ole_vstr2wc(property);
03925     hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, &IID_NULL,
03926                                                 pBuf, 1, lcid, &dispID);
03927     SysFreeString(pBuf[0]);
03928     pBuf[0] = NULL;
03929 
03930     if(FAILED(hr)) {
03931         ole_raise(hr, eWIN32OLERuntimeError,
03932                   "unknown property or method: `%s'",
03933                   StringValuePtr(property));
03934     }
03935     /* set property value */
03936     ole_val2variant(value, &propertyValue[0]);
03937     hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, dispID, &IID_NULL,
03938                                          lcid, wFlags, &dispParams,
03939                                          NULL, &excepinfo, &argErr);
03940 
03941     for(index = 0; index < dispParams.cArgs; ++index) {
03942         VariantClear(&propertyValue[index]);
03943     }
03944     if (FAILED(hr)) {
03945         v = ole_excepinfo2msg(&excepinfo);
03946         ole_raise(hr, eWIN32OLERuntimeError, "(in setting property `%s': )%s",
03947                   StringValuePtr(property),
03948                   StringValuePtr(v));
03949     }
03950     return Qnil;
03951 }
03952 
03953 /*
03954  *  call-seq:
03955  *     WIN32OLE#ole_free
03956  *
03957  *  invokes Release method of Dispatch interface of WIN32OLE object.
03958  *  Usually, you do not need to call this method because Release method
03959  *  called automatically when WIN32OLE object garbaged.
03960  *
03961  */
03962 static VALUE
03963 fole_free(VALUE self)
03964 {
03965     struct oledata *pole;
03966     rb_secure(4);
03967     OLEData_Get_Struct(self, pole);
03968     OLE_FREE(pole->pDispatch);
03969     pole->pDispatch = NULL;
03970     return Qnil;
03971 }
03972 
03973 static VALUE
03974 ole_each_sub(VALUE pEnumV)
03975 {
03976     VARIANT variant;
03977     VALUE obj = Qnil;
03978     IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
03979     VariantInit(&variant);
03980     while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) {
03981         obj = ole_variant2val(&variant);
03982         VariantClear(&variant);
03983         VariantInit(&variant);
03984         rb_yield(obj);
03985     }
03986     return Qnil;
03987 }
03988 
03989 static VALUE
03990 ole_ienum_free(VALUE pEnumV)
03991 {
03992     IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
03993     OLE_RELEASE(pEnum);
03994     return Qnil;
03995 }
03996 
03997 /*
03998  *  call-seq:
03999  *     WIN32OLE#each {|i|...}
04000  *
04001  *  Iterates over each item of OLE collection which has IEnumVARIANT interface.
04002  *
04003  *     excel = WIN32OLE.new('Excel.Application')
04004  *     book = excel.workbooks.add
04005  *     sheets = book.worksheets(1)
04006  *     cells = sheets.cells("A1:A5")
04007  *     cells.each do |cell|
04008  *       cell.value = 10
04009  *     end
04010  */
04011 static VALUE
04012 fole_each(VALUE self)
04013 {
04014     LCID    lcid = cWIN32OLE_lcid;
04015 
04016     struct oledata *pole;
04017 
04018     unsigned int argErr;
04019     EXCEPINFO excepinfo;
04020     DISPPARAMS dispParams;
04021     VARIANT result;
04022     HRESULT hr;
04023     IEnumVARIANT *pEnum = NULL;
04024     void *p;
04025 
04026     RETURN_ENUMERATOR(self, 0, 0);
04027 
04028     VariantInit(&result);
04029     dispParams.rgvarg = NULL;
04030     dispParams.rgdispidNamedArgs = NULL;
04031     dispParams.cNamedArgs = 0;
04032     dispParams.cArgs = 0;
04033     memset(&excepinfo, 0, sizeof(excepinfo));
04034 
04035     OLEData_Get_Struct(self, pole);
04036     hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DISPID_NEWENUM,
04037                                          &IID_NULL, lcid,
04038                                          DISPATCH_METHOD | DISPATCH_PROPERTYGET,
04039                                          &dispParams, &result,
04040                                          &excepinfo, &argErr);
04041 
04042     if (FAILED(hr)) {
04043         VariantClear(&result);
04044         ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface");
04045     }
04046 
04047     if (V_VT(&result) == VT_UNKNOWN) {
04048         hr = V_UNKNOWN(&result)->lpVtbl->QueryInterface(V_UNKNOWN(&result),
04049                                                         &IID_IEnumVARIANT,
04050                                                         &p);
04051         pEnum = p;
04052     } else if (V_VT(&result) == VT_DISPATCH) {
04053         hr = V_DISPATCH(&result)->lpVtbl->QueryInterface(V_DISPATCH(&result),
04054                                                          &IID_IEnumVARIANT,
04055                                                          &p);
04056         pEnum = p;
04057     }
04058     if (FAILED(hr) || !pEnum) {
04059         VariantClear(&result);
04060         ole_raise(hr, rb_eRuntimeError, "failed to get IEnum Interface");
04061     }
04062 
04063     VariantClear(&result);
04064     rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum);
04065     return Qnil;
04066 }
04067 
04068 /*
04069  *  call-seq:
04070  *     WIN32OLE#method_missing(id [,arg1, arg2, ...])
04071  *
04072  *  Calls WIN32OLE#invoke method.
04073  */
04074 static VALUE
04075 fole_missing(int argc, VALUE *argv, VALUE self)
04076 {
04077     ID id;
04078     const char* mname;
04079     int n;
04080     id = rb_to_id(argv[0]);
04081     mname = rb_id2name(id);
04082     if(!mname) {
04083         rb_raise(rb_eRuntimeError, "fail: unknown method or property");
04084     }
04085     n = strlen(mname);
04086     if(mname[n-1] == '=') {
04087         argv[0] = rb_enc_str_new(mname, n-1, cWIN32OLE_enc);
04088 
04089         return ole_propertyput(self, argv[0], argv[1]);
04090     }
04091     else {
04092         argv[0] = rb_enc_str_new(mname, n, cWIN32OLE_enc);
04093         return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
04094     }
04095 }
04096 
04097 static VALUE
04098 ole_method_sub(VALUE self, ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE name)
04099 {
04100     HRESULT hr;
04101     TYPEATTR *pTypeAttr;
04102     BSTR bstr;
04103     FUNCDESC *pFuncDesc;
04104     WORD i;
04105     VALUE fname;
04106     VALUE method = Qnil;
04107     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
04108     if (FAILED(hr)) {
04109         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
04110     }
04111     for(i = 0; i < pTypeAttr->cFuncs && method == Qnil; i++) {
04112         hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, i, &pFuncDesc);
04113         if (FAILED(hr))
04114              continue;
04115 
04116         hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
04117                                                  &bstr, NULL, NULL, NULL);
04118         if (FAILED(hr)) {
04119             pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
04120             continue;
04121         }
04122         fname = WC2VSTR(bstr);
04123         if (strcasecmp(StringValuePtr(name), StringValuePtr(fname)) == 0) {
04124             olemethod_set_member(self, pTypeInfo, pOwnerTypeInfo, i, fname);
04125             method = self;
04126         }
04127         pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
04128         pFuncDesc=NULL;
04129     }
04130     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
04131     return method;
04132 }
04133 
04134 static VALUE
04135 olemethod_from_typeinfo(VALUE self, ITypeInfo *pTypeInfo, VALUE name)
04136 {
04137     HRESULT hr;
04138     TYPEATTR *pTypeAttr;
04139     WORD i;
04140     HREFTYPE href;
04141     ITypeInfo *pRefTypeInfo;
04142     VALUE method = Qnil;
04143     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
04144     if (FAILED(hr)) {
04145         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
04146     }
04147     method = ole_method_sub(self, 0, pTypeInfo, name);
04148     if (method != Qnil) {
04149        return method;
04150     }
04151     for(i=0; i < pTypeAttr->cImplTypes && method == Qnil; i++){
04152        hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
04153        if(FAILED(hr))
04154            continue;
04155        hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
04156        if (FAILED(hr))
04157            continue;
04158        method = ole_method_sub(self, pTypeInfo, pRefTypeInfo, name);
04159        OLE_RELEASE(pRefTypeInfo);
04160     }
04161     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
04162     return method;
04163 }
04164 
04165 static VALUE
04166 ole_methods_sub(ITypeInfo *pOwnerTypeInfo, ITypeInfo *pTypeInfo, VALUE methods, int mask)
04167 {
04168     HRESULT hr;
04169     TYPEATTR *pTypeAttr;
04170     BSTR bstr;
04171     FUNCDESC *pFuncDesc;
04172     VALUE method;
04173     WORD i;
04174     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
04175     if (FAILED(hr)) {
04176         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
04177     }
04178     for(i = 0; i < pTypeAttr->cFuncs; i++) {
04179         hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, i, &pFuncDesc);
04180         if (FAILED(hr))
04181              continue;
04182 
04183         hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
04184                                                  &bstr, NULL, NULL, NULL);
04185         if (FAILED(hr)) {
04186             pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
04187             continue;
04188         }
04189         if(pFuncDesc->invkind & mask) {
04190             method = folemethod_s_allocate(cWIN32OLE_METHOD);
04191             olemethod_set_member(method, pTypeInfo, pOwnerTypeInfo,
04192                                  i, WC2VSTR(bstr));
04193             rb_ary_push(methods, method);
04194         }
04195         pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
04196         pFuncDesc=NULL;
04197     }
04198     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
04199 
04200     return methods;
04201 }
04202 
04203 static VALUE
04204 ole_methods_from_typeinfo(ITypeInfo *pTypeInfo, int mask)
04205 {
04206     HRESULT hr;
04207     TYPEATTR *pTypeAttr;
04208     WORD i;
04209     HREFTYPE href;
04210     ITypeInfo *pRefTypeInfo;
04211     VALUE methods = rb_ary_new();
04212     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
04213     if (FAILED(hr)) {
04214         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
04215     }
04216 
04217     ole_methods_sub(0, pTypeInfo, methods, mask);
04218     for(i=0; i < pTypeAttr->cImplTypes; i++){
04219        hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
04220        if(FAILED(hr))
04221            continue;
04222        hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
04223        if (FAILED(hr))
04224            continue;
04225        ole_methods_sub(pTypeInfo, pRefTypeInfo, methods, mask);
04226        OLE_RELEASE(pRefTypeInfo);
04227     }
04228     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
04229     return methods;
04230 }
04231 
04232 static HRESULT
04233 typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti)
04234 {
04235     ITypeInfo *pTypeInfo;
04236     ITypeLib *pTypeLib;
04237     BSTR bstr;
04238     VALUE type;
04239     UINT i;
04240     UINT count;
04241     LCID    lcid = cWIN32OLE_lcid;
04242     HRESULT hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
04243                                                       0, lcid, &pTypeInfo);
04244     if(FAILED(hr)) {
04245         ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
04246     }
04247     hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo,
04248                                              -1,
04249                                              &bstr,
04250                                              NULL, NULL, NULL);
04251     type = WC2VSTR(bstr);
04252     hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
04253     OLE_RELEASE(pTypeInfo);
04254     if (FAILED(hr)) {
04255         ole_raise(hr, rb_eRuntimeError, "failed to GetContainingTypeLib");
04256     }
04257     count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
04258     for (i = 0; i < count; i++) {
04259         hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
04260                                                 &bstr, NULL, NULL, NULL);
04261         if (SUCCEEDED(hr) && rb_str_cmp(WC2VSTR(bstr), type) == 0) {
04262             hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
04263             if (SUCCEEDED(hr)) {
04264                 *ppti = pTypeInfo;
04265                 break;
04266             }
04267         }
04268     }
04269     OLE_RELEASE(pTypeLib);
04270     return hr;
04271 }
04272 
04273 static VALUE
04274 ole_methods(VALUE self, int mask)
04275 {
04276     ITypeInfo *pTypeInfo;
04277     HRESULT hr;
04278     VALUE methods;
04279     struct oledata *pole;
04280 
04281     OLEData_Get_Struct(self, pole);
04282     methods = rb_ary_new();
04283 
04284     hr = typeinfo_from_ole(pole, &pTypeInfo);
04285     if(FAILED(hr))
04286         return methods;
04287     rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask));
04288     OLE_RELEASE(pTypeInfo);
04289     return methods;
04290 }
04291 
04292 /*
04293  *  call-seq:
04294  *     WIN32OLE#ole_methods
04295  *
04296  *  Returns the array of WIN32OLE_METHOD object.
04297  *  The element is OLE method of WIN32OLE object.
04298  *
04299  *     excel = WIN32OLE.new('Excel.Application')
04300  *     methods = excel.ole_methods
04301  *
04302  */
04303 static VALUE
04304 fole_methods(VALUE self)
04305 {
04306     return ole_methods( self, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
04307 }
04308 
04309 /*
04310  *  call-seq:
04311  *     WIN32OLE#ole_get_methods
04312  *
04313  *  Returns the array of WIN32OLE_METHOD object .
04314  *  The element of the array is property (gettable) of WIN32OLE object.
04315  *
04316  *     excel = WIN32OLE.new('Excel.Application')
04317  *     properties = excel.ole_get_methods
04318  */
04319 static VALUE
04320 fole_get_methods(VALUE self)
04321 {
04322     return ole_methods( self, INVOKE_PROPERTYGET);
04323 }
04324 
04325 /*
04326  *  call-seq:
04327  *     WIN32OLE#ole_put_methods
04328  *
04329  *  Returns the array of WIN32OLE_METHOD object .
04330  *  The element of the array is property (settable) of WIN32OLE object.
04331  *
04332  *     excel = WIN32OLE.new('Excel.Application')
04333  *     properties = excel.ole_put_methods
04334  */
04335 static VALUE
04336 fole_put_methods(VALUE self)
04337 {
04338     return ole_methods( self, INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF);
04339 }
04340 
04341 /*
04342  *  call-seq:
04343  *     WIN32OLE#ole_func_methods
04344  *
04345  *  Returns the array of WIN32OLE_METHOD object .
04346  *  The element of the array is property (settable) of WIN32OLE object.
04347  *
04348  *     excel = WIN32OLE.new('Excel.Application')
04349  *     properties = excel.ole_func_methods
04350  *
04351  */
04352 static VALUE
04353 fole_func_methods(VALUE self)
04354 {
04355     return ole_methods( self, INVOKE_FUNC);
04356 }
04357 
04358 static VALUE
04359 ole_type_from_itypeinfo(ITypeInfo *pTypeInfo)
04360 {
04361     ITypeLib *pTypeLib;
04362     VALUE type = Qnil;
04363     HRESULT hr;
04364     unsigned int index;
04365     BSTR bstr;
04366 
04367     hr = pTypeInfo->lpVtbl->GetContainingTypeLib( pTypeInfo, &pTypeLib, &index );
04368     if(FAILED(hr)) {
04369         return Qnil;
04370     }
04371     hr = pTypeLib->lpVtbl->GetDocumentation( pTypeLib, index,
04372                                              &bstr, NULL, NULL, NULL);
04373     OLE_RELEASE(pTypeLib);
04374     if (FAILED(hr)) {
04375         return Qnil;
04376     }
04377     type = foletype_s_allocate(cWIN32OLE_TYPE);
04378     oletype_set_member(type, pTypeInfo, WC2VSTR(bstr));
04379     return type;
04380 }
04381 
04382 /*
04383  *   call-seq:
04384  *      WIN32OLE#ole_type
04385  *
04386  *   Returns WIN32OLE_TYPE object.
04387  *
04388  *      excel = WIN32OLE.new('Excel.Application')
04389  *      tobj = excel.ole_type
04390  */
04391 static VALUE
04392 fole_type(VALUE self)
04393 {
04394     ITypeInfo *pTypeInfo;
04395     HRESULT hr;
04396     struct oledata *pole;
04397     LCID  lcid = cWIN32OLE_lcid;
04398     VALUE type = Qnil;
04399 
04400     OLEData_Get_Struct(self, pole);
04401 
04402     hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo );
04403     if(FAILED(hr)) {
04404         ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
04405     }
04406     type = ole_type_from_itypeinfo(pTypeInfo);
04407     OLE_RELEASE(pTypeInfo);
04408     if (type == Qnil) {
04409         rb_raise(rb_eRuntimeError, "failed to create WIN32OLE_TYPE obj from ITypeInfo");
04410     }
04411     return type;
04412 }
04413 
04414 static VALUE
04415 ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo)
04416 {
04417     HRESULT hr;
04418     ITypeLib *pTypeLib;
04419     unsigned int index;
04420     VALUE retval = Qnil;
04421 
04422     hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
04423     if(FAILED(hr)) {
04424         return Qnil;
04425     }
04426     retval = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("allocate"), 0);
04427     oletypelib_set_member(retval, pTypeLib);
04428     return retval;
04429 }
04430 
04431 /*
04432  *  call-seq:
04433  *     WIN32OLE#ole_typelib -> The WIN32OLE_TYPELIB object
04434  *
04435  *  Returns the WIN32OLE_TYPELIB object. The object represents the
04436  *  type library which contains the WIN32OLE object.
04437  *
04438  *     excel = WIN32OLE.new('Excel.Application')
04439  *     tlib = excel.ole_typelib
04440  *     puts tlib.name  # -> 'Microsoft Excel 9.0 Object Library'
04441  */
04442 static VALUE
04443 fole_typelib(VALUE self)
04444 {
04445     struct oledata *pole;
04446     HRESULT hr;
04447     ITypeInfo *pTypeInfo;
04448     LCID  lcid = cWIN32OLE_lcid;
04449     VALUE vtlib = Qnil;
04450 
04451     OLEData_Get_Struct(self, pole);
04452     hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
04453                                               0, lcid, &pTypeInfo);
04454     if(FAILED(hr)) {
04455         ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo");
04456     }
04457     vtlib = ole_typelib_from_itypeinfo(pTypeInfo);
04458     OLE_RELEASE(pTypeInfo);
04459     if (vtlib == Qnil) {
04460         rb_raise(rb_eRuntimeError, "failed to get type library info.");
04461     }
04462     return vtlib;
04463 }
04464 
04465 /*
04466  *  call-seq:
04467  *     WIN32OLE#ole_query_interface(iid) -> WIN32OLE object
04468  *
04469  *  Returns WIN32OLE object for a specific dispatch or dual
04470  *  interface specified by iid.
04471  *
04472  *      ie = WIN32OLE.new('InternetExplorer.Application')
04473  *      ie_web_app = ie.ole_query_interface('{0002DF05-0000-0000-C000-000000000046}') # => WIN32OLE object for dispinterface IWebBrowserApp
04474  */
04475 static VALUE
04476 fole_query_interface(VALUE self, VALUE str_iid)
04477 {
04478     HRESULT hr;
04479     OLECHAR *pBuf;
04480     IID iid;
04481     struct oledata *pole;
04482     IDispatch *pDispatch;
04483     void *p;
04484 
04485     pBuf  = ole_vstr2wc(str_iid);
04486     hr = CLSIDFromString(pBuf, &iid);
04487     SysFreeString(pBuf);
04488     if(FAILED(hr)) {
04489         ole_raise(hr, eWIN32OLERuntimeError,
04490                   "invalid iid: `%s'",
04491                   StringValuePtr(str_iid));
04492     }
04493 
04494     OLEData_Get_Struct(self, pole);
04495     if(!pole->pDispatch) {
04496         rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
04497     }
04498 
04499     hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &iid,
04500                                                  &p);
04501     if(FAILED(hr)) {
04502         ole_raise(hr, eWIN32OLERuntimeError,
04503                   "failed to get interface `%s'",
04504                   StringValuePtr(str_iid));
04505     }
04506 
04507     pDispatch = p;
04508     return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
04509 }
04510 
04511 /*
04512  *  call-seq:
04513  *     WIN32OLE#ole_respond_to?(method) -> true or false
04514  *
04515  *  Returns true when OLE object has OLE method, otherwise returns false.
04516  *
04517  *      ie = WIN32OLE.new('InternetExplorer.Application')
04518  *      ie.ole_respond_to?("gohome") => true
04519  */
04520 static VALUE
04521 fole_respond_to(VALUE self, VALUE method)
04522 {
04523     struct oledata *pole;
04524     BSTR wcmdname;
04525     DISPID DispID;
04526     HRESULT hr;
04527     rb_secure(4);
04528     if(TYPE(method) != T_STRING && TYPE(method) != T_SYMBOL) {
04529         rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
04530     }
04531     if (TYPE(method) == T_SYMBOL) {
04532         method = rb_sym_to_s(method);
04533     }
04534     OLEData_Get_Struct(self, pole);
04535     wcmdname = ole_vstr2wc(method);
04536     hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
04537             &wcmdname, 1, cWIN32OLE_lcid, &DispID);
04538     SysFreeString(wcmdname);
04539     return SUCCEEDED(hr) ? Qtrue : Qfalse;
04540 }
04541 
04542 static HRESULT
04543 ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile)
04544 {
04545     HRESULT hr;
04546     ITypeLib *pTypeLib;
04547     UINT i;
04548 
04549     hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
04550     if (FAILED(hr)) {
04551         return hr;
04552     }
04553 
04554     hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
04555                                             name, helpstr,
04556                                             helpcontext, helpfile);
04557     if (FAILED(hr)) {
04558         OLE_RELEASE(pTypeLib);
04559         return hr;
04560     }
04561     OLE_RELEASE(pTypeLib);
04562     return hr;
04563 }
04564 
04565 static VALUE
04566 ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
04567 {
04568     HRESULT hr;
04569     BSTR bstr;
04570     ITypeInfo *pRefTypeInfo;
04571     VALUE type = Qnil;
04572 
04573     hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
04574                                            V_UNION1(pTypeDesc, hreftype),
04575                                            &pRefTypeInfo);
04576     if(FAILED(hr))
04577         return Qnil;
04578     hr = ole_docinfo_from_type(pRefTypeInfo, &bstr, NULL, NULL, NULL);
04579     if(FAILED(hr)) {
04580         OLE_RELEASE(pRefTypeInfo);
04581         return Qnil;
04582     }
04583     OLE_RELEASE(pRefTypeInfo);
04584     type = WC2VSTR(bstr);
04585     if(typedetails != Qnil)
04586         rb_ary_push(typedetails, type);
04587     return type;
04588 }
04589 
04590 static VALUE
04591 ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
04592 {
04593     TYPEDESC *p = pTypeDesc;
04594     VALUE type = rb_str_new2("");
04595 
04596     if (p->vt == VT_PTR || p->vt == VT_SAFEARRAY) {
04597         p = V_UNION1(p, lptdesc);
04598         type = ole_typedesc2val(pTypeInfo, p, typedetails);
04599     }
04600     return type;
04601 }
04602 
04603 static VALUE
04604 ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
04605 {
04606     VALUE str;
04607     VALUE typestr = Qnil;
04608     switch(pTypeDesc->vt) {
04609     case VT_I2:
04610         typestr = rb_str_new2("I2");
04611         break;
04612     case VT_I4:
04613         typestr = rb_str_new2("I4");
04614         break;
04615     case VT_R4:
04616         typestr = rb_str_new2("R4");
04617         break;
04618     case VT_R8:
04619         typestr = rb_str_new2("R8");
04620         break;
04621     case VT_CY:
04622         typestr = rb_str_new2("CY");
04623         break;
04624     case VT_DATE:
04625         typestr = rb_str_new2("DATE");
04626         break;
04627     case VT_BSTR:
04628         typestr = rb_str_new2("BSTR");
04629         break;
04630     case VT_BOOL:
04631         typestr = rb_str_new2("BOOL");
04632         break;
04633     case VT_VARIANT:
04634         typestr = rb_str_new2("VARIANT");
04635         break;
04636     case VT_DECIMAL:
04637         typestr = rb_str_new2("DECIMAL");
04638         break;
04639     case VT_I1:
04640         typestr = rb_str_new2("I1");
04641         break;
04642     case VT_UI1:
04643         typestr = rb_str_new2("UI1");
04644         break;
04645     case VT_UI2:
04646         typestr = rb_str_new2("UI2");
04647         break;
04648     case VT_UI4:
04649         typestr = rb_str_new2("UI4");
04650         break;
04651 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
04652     case VT_I8:
04653         typestr = rb_str_new2("I8");
04654         break;
04655     case VT_UI8:
04656         typestr = rb_str_new2("UI8");
04657         break;
04658 #endif
04659     case VT_INT:
04660         typestr = rb_str_new2("INT");
04661         break;
04662     case VT_UINT:
04663         typestr = rb_str_new2("UINT");
04664         break;
04665     case VT_VOID:
04666         typestr = rb_str_new2("VOID");
04667         break;
04668     case VT_HRESULT:
04669         typestr = rb_str_new2("HRESULT");
04670         break;
04671     case VT_PTR:
04672         typestr = rb_str_new2("PTR");
04673         if(typedetails != Qnil)
04674             rb_ary_push(typedetails, typestr);
04675         return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
04676     case VT_SAFEARRAY:
04677         typestr = rb_str_new2("SAFEARRAY");
04678         if(typedetails != Qnil)
04679             rb_ary_push(typedetails, typestr);
04680         return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
04681     case VT_CARRAY:
04682         typestr = rb_str_new2("CARRAY");
04683         break;
04684     case VT_USERDEFINED:
04685         typestr = rb_str_new2("USERDEFINED");
04686         if (typedetails != Qnil)
04687             rb_ary_push(typedetails, typestr);
04688         str = ole_usertype2val(pTypeInfo, pTypeDesc, typedetails);
04689         if (str != Qnil) {
04690             return str;
04691         }
04692         return typestr;
04693     case VT_UNKNOWN:
04694         typestr = rb_str_new2("UNKNOWN");
04695         break;
04696     case VT_DISPATCH:
04697         typestr = rb_str_new2("DISPATCH");
04698         break;
04699     case VT_ERROR:
04700         typestr = rb_str_new2("ERROR");
04701         break;
04702     case VT_LPWSTR:
04703         typestr = rb_str_new2("LPWSTR");
04704         break;
04705     case VT_LPSTR:
04706         typestr = rb_str_new2("LPSTR");
04707         break;
04708     default:
04709         typestr = rb_str_new2("Unknown Type ");
04710         rb_str_concat(typestr, rb_fix2str(INT2FIX(pTypeDesc->vt), 10));
04711         break;
04712     }
04713     if (typedetails != Qnil)
04714         rb_ary_push(typedetails, typestr);
04715     return typestr;
04716 }
04717 
04718 /*
04719  *   call-seq:
04720  *      WIN32OLE#ole_method_help(method)
04721  *
04722  *   Returns WIN32OLE_METHOD object corresponding with method
04723  *   specified by 1st argument.
04724  *
04725  *      excel = WIN32OLE.new('Excel.Application')
04726  *      method = excel.ole_method_help('Quit')
04727  *
04728  */
04729 static VALUE
04730 fole_method_help(VALUE self, VALUE cmdname)
04731 {
04732     ITypeInfo *pTypeInfo;
04733     HRESULT hr;
04734     struct oledata *pole;
04735     VALUE method, obj;
04736 
04737     SafeStringValue(cmdname);
04738     OLEData_Get_Struct(self, pole);
04739     hr = typeinfo_from_ole(pole, &pTypeInfo);
04740     if(FAILED(hr))
04741         ole_raise(hr, rb_eRuntimeError, "failed to get ITypeInfo");
04742     method = folemethod_s_allocate(cWIN32OLE_METHOD);
04743     obj = olemethod_from_typeinfo(method, pTypeInfo, cmdname);
04744     OLE_RELEASE(pTypeInfo);
04745     if (obj == Qnil)
04746         rb_raise(eWIN32OLERuntimeError, "not found %s",
04747                  StringValuePtr(cmdname));
04748     return obj;
04749 }
04750 
04751 /*
04752  *  call-seq:
04753  *     WIN32OLE#ole_activex_initialize() -> Qnil
04754  *
04755  *  Initialize WIN32OLE object(ActiveX Control) by calling
04756  *  IPersistMemory::InitNew.
04757  *
04758  *  Before calling OLE method, some kind of the ActiveX controls
04759  *  created with MFC should be initialized by calling
04760  *  IPersistXXX::InitNew.
04761  *
04762  *  If and only if you received the exception "HRESULT error code:
04763  *  0x8000ffff catastrophic failure", try this method before
04764  *  invoking any ole_method.
04765  *
04766  *     obj = WIN32OLE.new("ProgID_or_GUID_of_ActiveX_Control")
04767  *     obj.ole_activex_initialize
04768  *     obj.method(...)
04769  *
04770  */
04771 static VALUE
04772 fole_activex_initialize(VALUE self)
04773 {
04774     struct oledata *pole;
04775     IPersistMemory *pPersistMemory;
04776     void *p;
04777 
04778     HRESULT hr = S_OK;
04779 
04780     OLEData_Get_Struct(self, pole);
04781 
04782     hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p);
04783     pPersistMemory = p;
04784     if (SUCCEEDED(hr)) {
04785         hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory);
04786         OLE_RELEASE(pPersistMemory);
04787         if (SUCCEEDED(hr)) {
04788             return Qnil;
04789         }
04790     }
04791 
04792     if (FAILED(hr)) {
04793         ole_raise(hr, eWIN32OLERuntimeError, "fail to initialize ActiveX control");
04794     }
04795 
04796     return Qnil;
04797 }
04798 
04799 /*
04800  *   call-seq:
04801  *      WIN32OLE_TYPE.ole_classes(typelib)
04802  *
04803  *   Returns array of WIN32OLE_TYPE objects defined by the <i>typelib</i> type library.
04804  *   This method will be OBSOLETE. Use WIN32OLE_TYPELIB.new(typelib).ole_classes instead.
04805  */
04806 static VALUE
04807 foletype_s_ole_classes(VALUE self, VALUE typelib)
04808 {
04809     VALUE obj;
04810 
04811     /*
04812     rb_warn("%s is obsolete; use %s instead.",
04813             "WIN32OLE_TYPE.ole_classes",
04814             "WIN32OLE_TYPELIB.new(typelib).ole_types");
04815     */
04816     obj = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("new"), 1, typelib);
04817     return rb_funcall(obj, rb_intern("ole_types"), 0);
04818 }
04819 
04820 /*
04821  *  call-seq:
04822  *     WIN32OLE_TYPE.typelibs
04823  *
04824  *  Returns array of type libraries.
04825  *  This method will be OBSOLETE. Use WIN32OLE_TYPELIB.typelibs.collect{|t| t.name} instead.
04826  *
04827  */
04828 static VALUE
04829 foletype_s_typelibs(VALUE self)
04830 {
04831     /*
04832     rb_warn("%s is obsolete. use %s instead.",
04833             "WIN32OLE_TYPE.typelibs",
04834             "WIN32OLE_TYPELIB.typelibs.collect{t|t.name}");
04835     */
04836     return rb_eval_string("WIN32OLE_TYPELIB.typelibs.collect{|t|t.name}");
04837 }
04838 
04839 /*
04840  *  call-seq:
04841  *     WIN32OLE_TYPE.progids
04842  *
04843  *  Returns array of ProgID.
04844  */
04845 static VALUE
04846 foletype_s_progids(VALUE self)
04847 {
04848     HKEY hclsids, hclsid;
04849     DWORD i;
04850     LONG err;
04851     VALUE clsid;
04852     VALUE v = rb_str_new2("");
04853     VALUE progids = rb_ary_new();
04854 
04855     err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hclsids);
04856     if(err != ERROR_SUCCESS) {
04857         return progids;
04858     }
04859     for(i = 0; ; i++) {
04860         clsid = reg_enum_key(hclsids, i);
04861         if (clsid == Qnil)
04862             break;
04863         err = reg_open_vkey(hclsids, clsid, &hclsid);
04864         if (err != ERROR_SUCCESS)
04865             continue;
04866         if ((v = reg_get_val2(hclsid, "ProgID")) != Qnil)
04867             rb_ary_push(progids, v);
04868         if ((v = reg_get_val2(hclsid, "VersionIndependentProgID")) != Qnil)
04869             rb_ary_push(progids, v);
04870         RegCloseKey(hclsid);
04871     }
04872     RegCloseKey(hclsids);
04873     return progids;
04874 }
04875 
04876 static VALUE
04877 foletype_s_allocate(VALUE klass)
04878 {
04879     struct oletypedata *poletype;
04880     VALUE obj;
04881     ole_initialize();
04882     obj = Data_Make_Struct(klass,struct oletypedata,0,oletype_free,poletype);
04883     poletype->pTypeInfo = NULL;
04884     return obj;
04885 }
04886 
04887 static VALUE
04888 oletype_set_member(VALUE self, ITypeInfo *pTypeInfo, VALUE name)
04889 {
04890     struct oletypedata *ptype;
04891     Data_Get_Struct(self, struct oletypedata, ptype);
04892     rb_ivar_set(self, rb_intern("name"), name);
04893     ptype->pTypeInfo = pTypeInfo;
04894     if(pTypeInfo) OLE_ADDREF(pTypeInfo);
04895     return self;
04896 }
04897 
04898 static VALUE
04899 oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass)
04900 {
04901 
04902     long count;
04903     int i;
04904     HRESULT hr;
04905     BSTR bstr;
04906     VALUE typelib;
04907     ITypeInfo *pTypeInfo;
04908 
04909     VALUE found = Qfalse;
04910 
04911     count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
04912     for (i = 0; i < count && found == Qfalse; i++) {
04913         hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
04914         if (FAILED(hr))
04915             continue;
04916         hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
04917                                                 &bstr, NULL, NULL, NULL);
04918         if (FAILED(hr))
04919             continue;
04920         typelib = WC2VSTR(bstr);
04921         if (rb_str_cmp(oleclass, typelib) == 0) {
04922             oletype_set_member(self, pTypeInfo, typelib);
04923             found = Qtrue;
04924         }
04925         OLE_RELEASE(pTypeInfo);
04926     }
04927     return found;
04928 }
04929 
04930 /*
04931  * Document-class: WIN32OLE_TYPELIB
04932  *
04933  *   <code>WIN32OLE_TYPELIB</code> objects represent OLE tyblib information.
04934  */
04935 
04936 static VALUE
04937 oletypelib_set_member(VALUE self, ITypeLib *pTypeLib)
04938 {
04939     struct oletypelibdata *ptlib;
04940     Data_Get_Struct(self, struct oletypelibdata, ptlib);
04941     ptlib->pTypeLib = pTypeLib;
04942     return self;
04943 }
04944 
04945 static ITypeLib *
04946 oletypelib_get_typelib(VALUE self)
04947 {
04948     struct oletypelibdata *ptlib;
04949     Data_Get_Struct(self, struct oletypelibdata, ptlib);
04950     return ptlib->pTypeLib;
04951 }
04952 
04953 static void
04954 oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr)
04955 {
04956     HRESULT hr;
04957     hr = pTypeLib->lpVtbl->GetLibAttr(pTypeLib, ppTLibAttr);
04958     if (FAILED(hr)) {
04959         ole_raise(hr, eWIN32OLERuntimeError,
04960                   "failed to get library attribute(TLIBATTR) from ITypeLib");
04961     }
04962 }
04963 
04964 /*
04965  *  call-seq:
04966  *
04967  *     WIN32OLE_TYPELIB.typelibs
04968  *
04969  *  Returns the array of WIN32OLE_TYPELIB object.
04970  *
04971  *     tlibs = WIN32OLE_TYPELIB.typelibs
04972  *
04973  */
04974 static VALUE
04975 foletypelib_s_typelibs(VALUE self)
04976 {
04977     HKEY htypelib, hguid;
04978     DWORD i, j;
04979     LONG err;
04980     VALUE guid;
04981     VALUE version;
04982     VALUE name = Qnil;
04983     VALUE typelibs = rb_ary_new();
04984     VALUE typelib = Qnil;
04985     HRESULT hr;
04986     ITypeLib *pTypeLib;
04987 
04988     err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
04989     if(err != ERROR_SUCCESS) {
04990         return typelibs;
04991     }
04992     for(i = 0; ; i++) {
04993         guid = reg_enum_key(htypelib, i);
04994         if (guid == Qnil)
04995             break;
04996         err = reg_open_vkey(htypelib, guid, &hguid);
04997         if (err != ERROR_SUCCESS)
04998             continue;
04999         for(j = 0; ; j++) {
05000             version = reg_enum_key(hguid, j);
05001             if (version == Qnil)
05002                 break;
05003             if ( (name = reg_get_val2(hguid, StringValuePtr(version))) != Qnil ) {
05004                 hr = oletypelib_from_guid(guid, version, &pTypeLib);
05005                 if (SUCCEEDED(hr)) {
05006                     typelib = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("allocate"), 0);
05007                     oletypelib_set_member(typelib, pTypeLib);
05008                     rb_ary_push(typelibs, typelib);
05009                 }
05010             }
05011         }
05012         RegCloseKey(hguid);
05013     }
05014     RegCloseKey(htypelib);
05015     return typelibs;
05016 }
05017 
05018 static VALUE
05019 make_version_str(VALUE major, VALUE minor)
05020 {
05021     VALUE version_str = Qnil;
05022     VALUE minor_str = Qnil;
05023     if (major == Qnil) {
05024         return Qnil;
05025     }
05026     version_str = rb_String(major);
05027     if (minor != Qnil) {
05028         minor_str = rb_String(minor);
05029         rb_str_cat2(version_str, ".");
05030         rb_str_append(version_str, minor_str);
05031     }
05032     return version_str;
05033 }
05034 
05035 static VALUE
05036 oletypelib_search_registry2(VALUE self, VALUE args)
05037 {
05038     HKEY htypelib, hguid, hversion;
05039     double fver;
05040     DWORD j;
05041     LONG err;
05042     VALUE found = Qfalse;
05043     VALUE tlib;
05044     VALUE ver;
05045     VALUE version_str;
05046     VALUE version = Qnil;
05047     VALUE typelib = Qnil;
05048     HRESULT hr;
05049     ITypeLib *pTypeLib;
05050 
05051     VALUE guid = rb_ary_entry(args, 0);
05052     version_str = make_version_str(rb_ary_entry(args, 1), rb_ary_entry(args, 2));
05053 
05054     err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
05055     if(err != ERROR_SUCCESS) {
05056         return Qfalse;
05057     }
05058     err = reg_open_vkey(htypelib, guid, &hguid);
05059     if (err != ERROR_SUCCESS) {
05060         RegCloseKey(htypelib);
05061         return Qfalse;
05062     }
05063     if (version_str != Qnil) {
05064         err = reg_open_vkey(hguid, version_str, &hversion);
05065         if (err == ERROR_SUCCESS) {
05066             tlib = reg_get_val(hversion, NULL);
05067             if (tlib != Qnil) {
05068                 typelib = tlib;
05069                 version = version_str;
05070             }
05071         }
05072         RegCloseKey(hversion);
05073     } else {
05074         fver = 0.0;
05075             for(j = 0; ;j++) {
05076                 ver = reg_enum_key(hguid, j);
05077                 if (ver == Qnil)
05078                     break;
05079                 err = reg_open_vkey(hguid, ver, &hversion);
05080                 if (err != ERROR_SUCCESS)
05081                     continue;
05082                 tlib = reg_get_val(hversion, NULL);
05083                 if (tlib == Qnil) {
05084                      RegCloseKey(hversion);
05085                      continue;
05086                 }
05087                 if (fver < atof(StringValuePtr(ver))) {
05088                     fver = atof(StringValuePtr(ver));
05089                     version = ver;
05090                     typelib = tlib;
05091                 }
05092                 RegCloseKey(hversion);
05093             }
05094     }
05095     RegCloseKey(hguid);
05096     RegCloseKey(htypelib);
05097     if (typelib != Qnil) {
05098         hr = oletypelib_from_guid(guid, version, &pTypeLib);
05099         if (SUCCEEDED(hr)) {
05100             found = Qtrue;
05101             oletypelib_set_member(self, pTypeLib);
05102         }
05103     }
05104     return found;
05105 }
05106 
05107 static VALUE
05108 oletypelib_search_registry(VALUE self, VALUE typelib)
05109 {
05110     HKEY htypelib, hguid, hversion;
05111     DWORD i, j;
05112     LONG err;
05113     VALUE found = Qfalse;
05114     VALUE tlib;
05115     VALUE guid;
05116     VALUE ver;
05117     HRESULT hr;
05118     ITypeLib *pTypeLib;
05119 
05120     err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
05121     if(err != ERROR_SUCCESS) {
05122         return Qfalse;
05123     }
05124     for(i = 0; !found; i++) {
05125         guid = reg_enum_key(htypelib, i);
05126         if (guid == Qnil)
05127             break;
05128         err = reg_open_vkey(htypelib, guid, &hguid);
05129         if (err != ERROR_SUCCESS)
05130             continue;
05131         for(j = 0; found == Qfalse; j++) {
05132             ver = reg_enum_key(hguid, j);
05133             if (ver == Qnil)
05134                 break;
05135             err = reg_open_vkey(hguid, ver, &hversion);
05136             if (err != ERROR_SUCCESS)
05137                 continue;
05138             tlib = reg_get_val(hversion, NULL);
05139             if (tlib == Qnil) {
05140                 RegCloseKey(hversion);
05141                 continue;
05142             }
05143             if (rb_str_cmp(typelib, tlib) == 0) {
05144                 hr = oletypelib_from_guid(guid, ver, &pTypeLib);
05145                 if (SUCCEEDED(hr)) {
05146                     oletypelib_set_member(self, pTypeLib);
05147                     found = Qtrue;
05148                 }
05149             }
05150             RegCloseKey(hversion);
05151         }
05152         RegCloseKey(hguid);
05153     }
05154     RegCloseKey(htypelib);
05155     return  found;
05156 }
05157 
05158 static VALUE
05159 foletypelib_s_allocate(VALUE klass)
05160 {
05161     struct oletypelibdata *poletypelib;
05162     VALUE obj;
05163     ole_initialize();
05164     obj = Data_Make_Struct(klass, struct oletypelibdata, 0, oletypelib_free, poletypelib);
05165     poletypelib->pTypeLib = NULL;
05166     return obj;
05167 }
05168 
05169 /*
05170  * call-seq:
05171  *    WIN32OLE_TYPELIB.new(typelib [, version1, version2]) -> WIN32OLE_TYPELIB object
05172  *
05173  * Returns a new WIN32OLE_TYPELIB object.
05174  *
05175  * The first argument <i>typelib</i>  specifies OLE type library name or GUID or
05176  * OLE library file.
05177  * The second argument is major version or version of the type library.
05178  * The third argument is minor version.
05179  * The second argument and third argument are optional.
05180  * If the first argument is type library name, then the second and third argument
05181  * are ignored.
05182  *
05183  *     tlib1 = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05184  *     tlib2 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}')
05185  *     tlib3 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1.3)
05186  *     tlib4 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1, 3)
05187  *     tlib5 = WIN32OLE_TYPELIB.new("C:\\WINNT\\SYSTEM32\\SHELL32.DLL")
05188  *     puts tlib1.name  # -> 'Microsoft Excel 9.0 Object Library'
05189  *     puts tlib2.name  # -> 'Microsoft Excel 9.0 Object Library'
05190  *     puts tlib3.name  # -> 'Microsoft Excel 9.0 Object Library'
05191  *     puts tlib4.name  # -> 'Microsoft Excel 9.0 Object Library'
05192  *     puts tlib5.name  # -> 'Microsoft Shell Controls And Automation'
05193  *
05194  */
05195 static VALUE
05196 foletypelib_initialize(VALUE self, VALUE args)
05197 {
05198     VALUE found = Qfalse;
05199     VALUE typelib = Qnil;
05200     int len = 0;
05201     OLECHAR * pbuf;
05202     ITypeLib *pTypeLib;
05203     HRESULT hr = S_OK;
05204 
05205     len = RARRAY_LEN(args);
05206     if (len < 1 || len > 3) {
05207         rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", len);
05208     }
05209 
05210     typelib = rb_ary_entry(args, 0);
05211 
05212     SafeStringValue(typelib);
05213 
05214     found = oletypelib_search_registry(self, typelib);
05215     if (found == Qfalse) {
05216         found = oletypelib_search_registry2(self, args);
05217     }
05218     if (found == Qfalse) {
05219         pbuf = ole_vstr2wc(typelib);
05220         hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib);
05221         SysFreeString(pbuf);
05222         if (SUCCEEDED(hr)) {
05223             found = Qtrue;
05224             oletypelib_set_member(self, pTypeLib);
05225         }
05226     }
05227 
05228     if (found == Qfalse) {
05229         rb_raise(eWIN32OLERuntimeError, "not found type library `%s`",
05230                  StringValuePtr(typelib));
05231     }
05232     return self;
05233 }
05234 
05235 /*
05236  *  call-seq:
05237  *     WIN32OLE_TYPELIB#guid -> The guid string.
05238  *
05239  *  Returns guid string which specifies type library.
05240  *
05241  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05242  *     guid = tlib.guid # -> '{00020813-0000-0000-C000-000000000046}'
05243  */
05244 static VALUE
05245 foletypelib_guid(VALUE self)
05246 {
05247     ITypeLib *pTypeLib;
05248     OLECHAR bstr[80];
05249     VALUE guid = Qnil;
05250     int len;
05251     TLIBATTR *pTLibAttr;
05252 
05253     pTypeLib = oletypelib_get_typelib(self);
05254     oletypelib_get_libattr(pTypeLib, &pTLibAttr);
05255     len = StringFromGUID2(&pTLibAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
05256     if (len > 3) {
05257         guid = ole_wc2vstr(bstr, FALSE);
05258     }
05259     pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05260     return guid;
05261 }
05262 
05263 /*
05264  *  call-seq:
05265  *     WIN32OLE_TYPELIB#name -> The type library name
05266  *
05267  *  Returns the type library name.
05268  *
05269  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05270  *     name = tlib.name # -> 'Microsoft Excel 9.0 Object Library'
05271  */
05272 static VALUE
05273 foletypelib_name(VALUE self)
05274 {
05275     ITypeLib *pTypeLib;
05276     HRESULT hr;
05277     BSTR bstr;
05278     VALUE name;
05279     pTypeLib = oletypelib_get_typelib(self);
05280     hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1,
05281                                             NULL, &bstr, NULL, NULL);
05282 
05283     if (FAILED(hr)) {
05284         ole_raise(hr, eWIN32OLERuntimeError, "failed to get name from ITypeLib");
05285     }
05286     name = WC2VSTR(bstr);
05287     return rb_enc_str_new(StringValuePtr(name), strlen(StringValuePtr(name)), cWIN32OLE_enc);
05288 }
05289 
05290 /*
05291  *  call-seq:
05292  *     WIN32OLE_TYPELIB#version -> The type library version.
05293  *
05294  *  Returns the type library version.
05295  *
05296  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05297  *     puts tlib.version #-> 1.3
05298  */
05299 static VALUE
05300 foletypelib_version(VALUE self)
05301 {
05302     TLIBATTR *pTLibAttr;
05303     VALUE major;
05304     VALUE minor;
05305     ITypeLib *pTypeLib;
05306 
05307     pTypeLib = oletypelib_get_typelib(self);
05308     oletypelib_get_libattr(pTypeLib, &pTLibAttr);
05309     major = INT2NUM(pTLibAttr->wMajorVerNum);
05310     minor = INT2NUM(pTLibAttr->wMinorVerNum);
05311     pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05312     return rb_Float(make_version_str(major, minor));
05313 }
05314 
05315 /*
05316  *  call-seq:
05317  *     WIN32OLE_TYPELIB#major_version -> The type library major version.
05318  *
05319  *  Returns the type library major version.
05320  *
05321  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05322  *     puts tlib.major_version # -> 1
05323  */
05324 static VALUE
05325 foletypelib_major_version(VALUE self)
05326 {
05327     TLIBATTR *pTLibAttr;
05328     VALUE major;
05329     ITypeLib *pTypeLib;
05330     pTypeLib = oletypelib_get_typelib(self);
05331     oletypelib_get_libattr(pTypeLib, &pTLibAttr);
05332 
05333     major =  INT2NUM(pTLibAttr->wMajorVerNum);
05334     pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05335     return major;
05336 }
05337 
05338 /*
05339  *  call-seq:
05340  *     WIN32OLE_TYPELIB#minor_version -> The type library minor version.
05341  *
05342  *  Returns the type library minor version.
05343  *
05344  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05345  *     puts tlib.minor_version # -> 3
05346  */
05347 static VALUE
05348 foletypelib_minor_version(VALUE self)
05349 {
05350     TLIBATTR *pTLibAttr;
05351     VALUE minor;
05352     ITypeLib *pTypeLib;
05353     pTypeLib = oletypelib_get_typelib(self);
05354     oletypelib_get_libattr(pTypeLib, &pTLibAttr);
05355     minor =  INT2NUM(pTLibAttr->wMinorVerNum);
05356     pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05357     return minor;
05358 }
05359 
05360 static VALUE
05361 oletypelib_path(VALUE guid, VALUE version)
05362 {
05363     int k;
05364     LONG err;
05365     HKEY hkey;
05366     HKEY hlang;
05367     VALUE lang;
05368     VALUE path = Qnil;
05369 
05370     VALUE key = rb_str_new2("TypeLib\\");
05371     rb_str_concat(key, guid);
05372     rb_str_cat2(key, "\\");
05373     rb_str_concat(key, version);
05374 
05375     err = reg_open_vkey(HKEY_CLASSES_ROOT, key, &hkey);
05376     if (err != ERROR_SUCCESS) {
05377         return Qnil;
05378     }
05379     for(k = 0; path == Qnil; k++) {
05380         lang = reg_enum_key(hkey, k);
05381         if (lang == Qnil)
05382             break;
05383         err = reg_open_vkey(hkey, lang, &hlang);
05384         if (err == ERROR_SUCCESS) {
05385             path = reg_get_typelib_file_path(hlang);
05386             RegCloseKey(hlang);
05387         }
05388     }
05389     RegCloseKey(hkey);
05390     return path;
05391 }
05392 
05393 static HRESULT
05394 oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib)
05395 {
05396     VALUE path;
05397     OLECHAR *pBuf;
05398     HRESULT hr;
05399     path = oletypelib_path(guid, version);
05400     if (path == Qnil) {
05401         return E_UNEXPECTED;
05402     }
05403     pBuf = ole_vstr2wc(path);
05404     hr = LoadTypeLibEx(pBuf, REGKIND_NONE, ppTypeLib);
05405     SysFreeString(pBuf);
05406     return hr;
05407 }
05408 
05409 /*
05410  *  call-seq:
05411  *     WIN32OLE_TYPELIB#path -> The type library file path.
05412  *
05413  *  Returns the type library file path.
05414  *
05415  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05416  *     puts tlib.path #-> 'C:\...\EXCEL9.OLB'
05417  */
05418 static VALUE
05419 foletypelib_path(VALUE self)
05420 {
05421     TLIBATTR *pTLibAttr;
05422     HRESULT hr = S_OK;
05423     BSTR bstr;
05424     LCID lcid = cWIN32OLE_lcid;
05425     VALUE path;
05426     ITypeLib *pTypeLib;
05427 
05428     pTypeLib = oletypelib_get_typelib(self);
05429     oletypelib_get_libattr(pTypeLib, &pTLibAttr);
05430     hr = QueryPathOfRegTypeLib(&pTLibAttr->guid,
05431                                pTLibAttr->wMajorVerNum,
05432                                pTLibAttr->wMinorVerNum,
05433                                lcid,
05434                                &bstr);
05435     if (FAILED(hr)) {
05436         pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05437         ole_raise(hr, eWIN32OLERuntimeError, "failed to QueryPathOfRegTypeTypeLib");
05438     }
05439 
05440     pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05441     path = WC2VSTR(bstr);
05442     return rb_enc_str_new(StringValuePtr(path), strlen(StringValuePtr(path)), cWIN32OLE_enc);
05443 }
05444 
05445 /*
05446  *  call-seq:
05447  *     WIN32OLE_TYPELIB#visible?
05448  *
05449  *  Returns true if the type library information is not hidden.
05450  *  If wLibFlags of TLIBATTR is 0 or LIBFLAG_FRESTRICTED or LIBFLAG_FHIDDEN,
05451  *  the method returns false, otherwise, returns true.
05452  *  If the method fails to access the TLIBATTR information, then
05453  *  WIN32OLERuntimeError is raised.
05454  *
05455  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05456  *     tlib.visible? # => true
05457  */
05458 static VALUE
05459 foletypelib_visible(VALUE self)
05460 {
05461     ITypeLib *pTypeLib = NULL;
05462     VALUE visible = Qtrue;
05463     TLIBATTR *pTLibAttr;
05464 
05465     pTypeLib = oletypelib_get_typelib(self);
05466     oletypelib_get_libattr(pTypeLib, &pTLibAttr);
05467 
05468     if ((pTLibAttr->wLibFlags == 0) ||
05469         (pTLibAttr->wLibFlags & LIBFLAG_FRESTRICTED) ||
05470         (pTLibAttr->wLibFlags & LIBFLAG_FHIDDEN)) {
05471         visible = Qfalse;
05472     }
05473     pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr);
05474     return visible;
05475 }
05476 
05477 /*
05478  *  call-seq:
05479  *     WIN32OLE_TYPELIB#library_name
05480  *
05481  *  Returns library name.
05482  *  If the method fails to access library name, WIN32OLERuntimeError is raised.
05483  *
05484  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05485  *     tlib.library_name # => Excel
05486  */
05487 static VALUE
05488 foletypelib_library_name(VALUE self)
05489 {
05490     HRESULT hr;
05491     ITypeLib *pTypeLib = NULL;
05492     VALUE libname = Qnil;
05493     BSTR bstr;
05494 
05495     pTypeLib = oletypelib_get_typelib(self);
05496     hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1,
05497                                             &bstr, NULL, NULL, NULL);
05498     if (FAILED(hr)) {
05499         ole_raise(hr, eWIN32OLERuntimeError, "failed to get library name");
05500     }
05501     libname = WC2VSTR(bstr);
05502     return libname;
05503 }
05504 
05505 
05506 /*
05507  *  call-seq:
05508  *     WIN32OLE_TYPELIB#ole_types -> The array of WIN32OLE_TYPE object included the type library.
05509  *
05510  *  Returns the type library file path.
05511  *
05512  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05513  *     classes = tlib.ole_types.collect{|k| k.name} # -> ['AddIn', 'AddIns' ...]
05514  */
05515 static VALUE
05516 foletypelib_ole_types(VALUE self)
05517 {
05518     ITypeLib *pTypeLib = NULL;
05519     VALUE classes = rb_ary_new();
05520     pTypeLib = oletypelib_get_typelib(self);
05521     ole_types_from_typelib(pTypeLib, classes);
05522     return classes;
05523 }
05524 
05525 /*
05526  *  call-seq:
05527  *     WIN32OLE_TYPELIB#inspect -> String
05528  *
05529  *  Returns the type library name with class name.
05530  *
05531  *     tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
05532  *     tlib.inspect # => "<#WIN32OLE_TYPELIB:Microsoft Excel 9.0 Object Library>"
05533  */
05534 static VALUE
05535 foletypelib_inspect(VALUE self)
05536 {
05537     return default_inspect(self, "WIN32OLE_TYPELIB");
05538 }
05539 
05540 /*
05541  * Document-class: WIN32OLE_TYPE
05542  *
05543  *   <code>WIN32OLE_TYPE</code> objects represent OLE type libarary information.
05544  */
05545 
05546 /*
05547  *  call-seq:
05548  *     WIN32OLE_TYPE.new(typelib, ole_class) -> WIN32OLE_TYPE object
05549  *
05550  *  Returns a new WIN32OLE_TYPE object.
05551  *  The first argument <i>typelib</i> specifies OLE type library name.
05552  *  The second argument specifies OLE class name.
05553  *
05554  *      WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
05555  *          # => WIN32OLE_TYPE object of Application class of Excel.
05556  */
05557 static VALUE
05558 foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass)
05559 {
05560     VALUE file;
05561     OLECHAR * pbuf;
05562     ITypeLib *pTypeLib;
05563     HRESULT hr;
05564 
05565     SafeStringValue(oleclass);
05566     SafeStringValue(typelib);
05567     file = typelib_file(typelib);
05568     if (file == Qnil) {
05569         file = typelib;
05570     }
05571     pbuf = ole_vstr2wc(file);
05572     hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib);
05573     if (FAILED(hr))
05574         ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx");
05575     SysFreeString(pbuf);
05576     if (oleclass_from_typelib(self, pTypeLib, oleclass) == Qfalse) {
05577         OLE_RELEASE(pTypeLib);
05578         rb_raise(eWIN32OLERuntimeError, "not found `%s` in `%s`",
05579                  StringValuePtr(oleclass), StringValuePtr(typelib));
05580     }
05581     OLE_RELEASE(pTypeLib);
05582     return self;
05583 }
05584 
05585 /*
05586  * call-seq:
05587  *    WIN32OLE_TYPE#name #=> OLE type name
05588  *
05589  * Returns OLE type name.
05590  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
05591  *    puts tobj.name  # => Application
05592  */
05593 static VALUE
05594 foletype_name(VALUE self)
05595 {
05596     return rb_ivar_get(self, rb_intern("name"));
05597 }
05598 
05599 static VALUE
05600 ole_ole_type(ITypeInfo *pTypeInfo)
05601 {
05602     HRESULT hr;
05603     TYPEATTR *pTypeAttr;
05604     VALUE type = Qnil;
05605     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05606     if(FAILED(hr)){
05607         return type;
05608     }
05609     switch(pTypeAttr->typekind) {
05610     case TKIND_ENUM:
05611         type = rb_str_new2("Enum");
05612         break;
05613     case TKIND_RECORD:
05614         type = rb_str_new2("Record");
05615         break;
05616     case TKIND_MODULE:
05617         type = rb_str_new2("Module");
05618         break;
05619     case TKIND_INTERFACE:
05620         type = rb_str_new2("Interface");
05621         break;
05622     case TKIND_DISPATCH:
05623         type = rb_str_new2("Dispatch");
05624         break;
05625     case TKIND_COCLASS:
05626         type = rb_str_new2("Class");
05627         break;
05628     case TKIND_ALIAS:
05629         type = rb_str_new2("Alias");
05630         break;
05631     case TKIND_UNION:
05632         type = rb_str_new2("Union");
05633         break;
05634     case TKIND_MAX:
05635         type = rb_str_new2("Max");
05636         break;
05637     default:
05638         type = Qnil;
05639         break;
05640     }
05641     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05642     return type;
05643 }
05644 
05645 /*
05646  *  call-seq:
05647  *     WIN32OLE_TYPE#ole_type #=> OLE type string.
05648  *
05649  *  returns type of OLE class.
05650  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
05651  *    puts tobj.ole_type  # => Class
05652  */
05653 static VALUE
05654 foletype_ole_type(VALUE self)
05655 {
05656     struct oletypedata *ptype;
05657     Data_Get_Struct(self, struct oletypedata, ptype);
05658     return ole_ole_type(ptype->pTypeInfo);
05659 }
05660 
05661 static VALUE
05662 ole_type_guid(ITypeInfo *pTypeInfo)
05663 {
05664     HRESULT hr;
05665     TYPEATTR *pTypeAttr;
05666     int len;
05667     OLECHAR bstr[80];
05668     VALUE guid = Qnil;
05669     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05670     if (FAILED(hr))
05671         return guid;
05672     len = StringFromGUID2(&pTypeAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
05673     if (len > 3) {
05674         guid = ole_wc2vstr(bstr, FALSE);
05675     }
05676     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05677     return guid;
05678 }
05679 
05680 /*
05681  *  call-seq:
05682  *     WIN32OLE_TYPE#guid  #=> GUID
05683  *
05684  *  Returns GUID.
05685  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
05686  *    puts tobj.guid  # => {00024500-0000-0000-C000-000000000046}
05687  */
05688 static VALUE
05689 foletype_guid(VALUE self)
05690 {
05691     struct oletypedata *ptype;
05692     Data_Get_Struct(self, struct oletypedata, ptype);
05693     return ole_type_guid(ptype->pTypeInfo);
05694 }
05695 
05696 static VALUE
05697 ole_type_progid(ITypeInfo *pTypeInfo)
05698 {
05699     HRESULT hr;
05700     TYPEATTR *pTypeAttr;
05701     OLECHAR *pbuf;
05702     VALUE progid = Qnil;
05703     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05704     if (FAILED(hr))
05705         return progid;
05706     hr = ProgIDFromCLSID(&pTypeAttr->guid, &pbuf);
05707     if (SUCCEEDED(hr)) {
05708         progid = ole_wc2vstr(pbuf, FALSE);
05709         CoTaskMemFree(pbuf);
05710     }
05711     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05712     return progid;
05713 }
05714 
05715 /*
05716  * call-seq:
05717  *    WIN32OLE_TYPE#progid  #=> ProgID
05718  *
05719  * Returns ProgID if it exists. If not found, then returns nil.
05720  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
05721  *    puts tobj.progid  # =>   Excel.Application.9
05722  */
05723 static VALUE
05724 foletype_progid(VALUE self)
05725 {
05726     struct oletypedata *ptype;
05727     Data_Get_Struct(self, struct oletypedata, ptype);
05728     return ole_type_progid(ptype->pTypeInfo);
05729 }
05730 
05731 
05732 static VALUE
05733 ole_type_visible(ITypeInfo *pTypeInfo)
05734 {
05735     HRESULT hr;
05736     TYPEATTR *pTypeAttr;
05737     VALUE visible;
05738     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05739     if (FAILED(hr))
05740         return Qtrue;
05741     if (pTypeAttr->wTypeFlags & (TYPEFLAG_FHIDDEN | TYPEFLAG_FRESTRICTED)) {
05742         visible = Qfalse;
05743     } else {
05744         visible = Qtrue;
05745     }
05746     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05747     return visible;
05748 }
05749 
05750 /*
05751  *  call-seq:
05752  *    WIN32OLE_TYPE#visible  #=> true or false
05753  *
05754  *  Returns true if the OLE class is public.
05755  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
05756  *    puts tobj.visible  # => true
05757  */
05758 static VALUE
05759 foletype_visible(VALUE self)
05760 {
05761     struct oletypedata *ptype;
05762     Data_Get_Struct(self, struct oletypedata, ptype);
05763     return ole_type_visible(ptype->pTypeInfo);
05764 }
05765 
05766 static VALUE
05767 ole_type_major_version(ITypeInfo *pTypeInfo)
05768 {
05769     VALUE ver;
05770     TYPEATTR *pTypeAttr;
05771     HRESULT hr;
05772     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05773     if (FAILED(hr))
05774         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
05775     ver = INT2FIX(pTypeAttr->wMajorVerNum);
05776     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05777     return ver;
05778 }
05779 
05780 /*
05781  *  call-seq:
05782  *     WIN32OLE_TYPE#major_version
05783  *
05784  *  Returns major version.
05785  *     tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
05786  *     puts tobj.major_version # => 8
05787  */
05788 static VALUE
05789 foletype_major_version(VALUE self)
05790 {
05791     struct oletypedata *ptype;
05792     Data_Get_Struct(self, struct oletypedata, ptype);
05793     return ole_type_major_version(ptype->pTypeInfo);
05794 }
05795 
05796 static VALUE
05797 ole_type_minor_version(ITypeInfo *pTypeInfo)
05798 {
05799     VALUE ver;
05800     TYPEATTR *pTypeAttr;
05801     HRESULT hr;
05802     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05803     if (FAILED(hr))
05804         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
05805     ver = INT2FIX(pTypeAttr->wMinorVerNum);
05806     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05807     return ver;
05808 }
05809 
05810 /*
05811  *  call-seq:
05812  *    WIN32OLE_TYPE#minor_version #=> OLE minor version
05813  *
05814  *  Returns minor version.
05815  *     tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
05816  *     puts tobj.minor_version # => 2
05817  */
05818 static VALUE
05819 foletype_minor_version(VALUE self)
05820 {
05821     struct oletypedata *ptype;
05822     Data_Get_Struct(self, struct oletypedata, ptype);
05823     return ole_type_minor_version(ptype->pTypeInfo);
05824 }
05825 
05826 static VALUE
05827 ole_type_typekind(ITypeInfo *pTypeInfo)
05828 {
05829     VALUE typekind;
05830     TYPEATTR *pTypeAttr;
05831     HRESULT hr;
05832     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05833     if (FAILED(hr))
05834         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
05835     typekind = INT2FIX(pTypeAttr->typekind);
05836     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05837     return typekind;
05838 }
05839 
05840 /*
05841  *  call-seq:
05842  *    WIN32OLE_TYPE#typekind #=> number of type.
05843  *
05844  *  Returns number which represents type.
05845  *    tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
05846  *    puts tobj.typekind # => 4
05847  *
05848  */
05849 static VALUE
05850 foletype_typekind(VALUE self)
05851 {
05852     struct oletypedata *ptype;
05853     Data_Get_Struct(self, struct oletypedata, ptype);
05854     return ole_type_typekind(ptype->pTypeInfo);
05855 }
05856 
05857 static VALUE
05858 ole_type_helpstring(ITypeInfo *pTypeInfo)
05859 {
05860     HRESULT hr;
05861     BSTR bhelpstr;
05862     hr = ole_docinfo_from_type(pTypeInfo, NULL, &bhelpstr, NULL, NULL);
05863     if(FAILED(hr)) {
05864         return Qnil;
05865     }
05866     return WC2VSTR(bhelpstr);
05867 }
05868 
05869 /*
05870  *  call-seq:
05871  *    WIN32OLE_TYPE#helpstring #=> help string.
05872  *
05873  *  Returns help string.
05874  *    tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'IWebBrowser')
05875  *    puts tobj.helpstring # => Web Browser interface
05876  */
05877 static VALUE
05878 foletype_helpstring(VALUE self)
05879 {
05880     struct oletypedata *ptype;
05881     Data_Get_Struct(self, struct oletypedata, ptype);
05882     return ole_type_helpstring(ptype->pTypeInfo);
05883 }
05884 
05885 static VALUE
05886 ole_type_src_type(ITypeInfo *pTypeInfo)
05887 {
05888     HRESULT hr;
05889     TYPEATTR *pTypeAttr;
05890     VALUE alias = Qnil;
05891     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
05892     if (FAILED(hr))
05893         return alias;
05894     if(pTypeAttr->typekind != TKIND_ALIAS) {
05895         OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05896         return alias;
05897     }
05898     alias = ole_typedesc2val(pTypeInfo, &(pTypeAttr->tdescAlias), Qnil);
05899     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
05900     return alias;
05901 }
05902 
05903 /*
05904  *  call-seq:
05905  *     WIN32OLE_TYPE#src_type #=> OLE source class
05906  *
05907  *  Returns source class when the OLE class is 'Alias'.
05908  *     tobj =  WIN32OLE_TYPE.new('Microsoft Office 9.0 Object Library', 'MsoRGBType')
05909  *     puts tobj.src_type # => I4
05910  *
05911  */
05912 static VALUE
05913 foletype_src_type(VALUE self)
05914 {
05915     struct oletypedata *ptype;
05916     Data_Get_Struct(self, struct oletypedata, ptype);
05917     return ole_type_src_type(ptype->pTypeInfo);
05918 }
05919 
05920 static VALUE
05921 ole_type_helpfile(ITypeInfo *pTypeInfo)
05922 {
05923     HRESULT hr;
05924     BSTR bhelpfile;
05925     hr = ole_docinfo_from_type(pTypeInfo, NULL, NULL, NULL, &bhelpfile);
05926     if(FAILED(hr)) {
05927         return Qnil;
05928     }
05929     return WC2VSTR(bhelpfile);
05930 }
05931 
05932 /*
05933  *  call-seq:
05934  *     WIN32OLE_TYPE#helpfile
05935  *
05936  *  Returns helpfile path. If helpfile is not found, then returns nil.
05937  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
05938  *     puts tobj.helpfile # => C:\...\VBAXL9.CHM
05939  *
05940  */
05941 static VALUE
05942 foletype_helpfile(VALUE self)
05943 {
05944     struct oletypedata *ptype;
05945     Data_Get_Struct(self, struct oletypedata, ptype);
05946     return ole_type_helpfile(ptype->pTypeInfo);
05947 }
05948 
05949 static VALUE
05950 ole_type_helpcontext(ITypeInfo *pTypeInfo)
05951 {
05952     HRESULT hr;
05953     DWORD helpcontext;
05954     hr = ole_docinfo_from_type(pTypeInfo, NULL, NULL,
05955                                &helpcontext, NULL);
05956     if(FAILED(hr))
05957         return Qnil;
05958     return INT2FIX(helpcontext);
05959 }
05960 
05961 /*
05962  *  call-seq:
05963  *     WIN32OLE_TYPE#helpcontext
05964  *
05965  *  Returns helpcontext. If helpcontext is not found, then returns nil.
05966  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
05967  *     puts tobj.helpfile # => 131185
05968  */
05969 static VALUE
05970 foletype_helpcontext(VALUE self)
05971 {
05972     struct oletypedata *ptype;
05973     Data_Get_Struct(self, struct oletypedata, ptype);
05974     return ole_type_helpcontext(ptype->pTypeInfo);
05975 }
05976 
05977 /*
05978  *  call-seq:
05979  *     WIN32OLE_TYPE#ole_typelib
05980  *
05981  *  Returns the WIN32OLE_TYPELIB object which is including the WIN32OLE_TYPE
05982  *  object. If it is not found, then returns nil.
05983  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
05984  *     puts tobj.ole_typelib # => 'Microsoft Excel 9.0 Object Library'
05985  */
05986 static VALUE
05987 foletype_ole_typelib(VALUE self)
05988 {
05989     struct oletypedata *ptype;
05990     Data_Get_Struct(self, struct oletypedata, ptype);
05991     return ole_typelib_from_itypeinfo(ptype->pTypeInfo);
05992 }
05993 
05994 static VALUE
05995 ole_type_impl_ole_types(ITypeInfo *pTypeInfo, int implflags)
05996 {
05997     HRESULT hr;
05998     ITypeInfo *pRefTypeInfo;
05999     HREFTYPE href;
06000     WORD i;
06001     VALUE type;
06002     TYPEATTR *pTypeAttr;
06003     int flags;
06004 
06005     VALUE types = rb_ary_new();
06006     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
06007     if (FAILED(hr)) {
06008         return types;
06009     }
06010     for (i = 0; i < pTypeAttr->cImplTypes; i++) {
06011         hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
06012         if (FAILED(hr))
06013             continue;
06014 
06015         hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
06016         if (FAILED(hr))
06017             continue;
06018         hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
06019         if (FAILED(hr))
06020             continue;
06021 
06022         if ((flags & implflags) == implflags) {
06023             type = ole_type_from_itypeinfo(pRefTypeInfo);
06024             if (type != Qnil) {
06025                 rb_ary_push(types, type);
06026             }
06027         }
06028 
06029         OLE_RELEASE(pRefTypeInfo);
06030     }
06031     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
06032     return types;
06033 }
06034 
06035 /*
06036  *  call-seq:
06037  *     WIN32OLE_TYPE#implemented_ole_types
06038  *
06039  *  Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
06040  *  object.
06041  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
06042  *     p tobj.implemented_ole_types # => [_Worksheet, DocEvents]
06043  */
06044 static VALUE
06045 foletype_impl_ole_types(VALUE self)
06046 {
06047     struct oletypedata *ptype;
06048     Data_Get_Struct(self, struct oletypedata, ptype);
06049     return ole_type_impl_ole_types(ptype->pTypeInfo, 0);
06050 }
06051 
06052 /*
06053  *  call-seq:
06054  *     WIN32OLE_TYPE#source_ole_types
06055  *
06056  *  Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
06057  *  object and having IMPLTYPEFLAG_FSOURCE.
06058  *     tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
06059  *     p tobj.source_ole_types
06060  *     # => [#<WIN32OLE_TYPE:DWebBrowserEvents2>, #<WIN32OLE_TYPE:DWebBrowserEvents>]
06061  */
06062 static VALUE
06063 foletype_source_ole_types(VALUE self)
06064 {
06065     struct oletypedata *ptype;
06066     Data_Get_Struct(self, struct oletypedata, ptype);
06067     return ole_type_impl_ole_types(ptype->pTypeInfo, IMPLTYPEFLAG_FSOURCE);
06068 }
06069 
06070 /*
06071  *  call-seq:
06072  *     WIN32OLE_TYPE#default_event_sources
06073  *
06074  *  Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
06075  *  object and having IMPLTYPEFLAG_FSOURCE and IMPLTYPEFLAG_FDEFAULT.
06076  *     tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
06077  *     p tobj.default_event_sources  # => [#<WIN32OLE_TYPE:DWebBrowserEvents2>]
06078  */
06079 static VALUE
06080 foletype_default_event_sources(VALUE self)
06081 {
06082     struct oletypedata *ptype;
06083     Data_Get_Struct(self, struct oletypedata, ptype);
06084     return ole_type_impl_ole_types(ptype->pTypeInfo, IMPLTYPEFLAG_FSOURCE|IMPLTYPEFLAG_FDEFAULT);
06085 }
06086 
06087 /*
06088  *  call-seq:
06089  *     WIN32OLE_TYPE#default_ole_types
06090  *
06091  *  Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
06092  *  object and having IMPLTYPEFLAG_FDEFAULT.
06093  *     tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
06094  *     p tobj.default_ole_types
06095  *     # => [#<WIN32OLE_TYPE:IWebBrowser2>, #<WIN32OLE_TYPE:DWebBrowserEvents2>]
06096  */
06097 static VALUE
06098 foletype_default_ole_types(VALUE self)
06099 {
06100     struct oletypedata *ptype;
06101     Data_Get_Struct(self, struct oletypedata, ptype);
06102     return ole_type_impl_ole_types(ptype->pTypeInfo, IMPLTYPEFLAG_FDEFAULT);
06103 }
06104 
06105 /*
06106  *  call-seq:
06107  *     WIN32OLE_TYPE#inspect -> String
06108  *
06109  *  Returns the type name with class name.
06110  *
06111  *     ie = WIN32OLE.new('InternetExplorer.Application')
06112  *     ie.ole_type.inspect => #<WIN32OLE_TYPE:IWebBrowser2>
06113  */
06114 static VALUE
06115 foletype_inspect(VALUE self)
06116 {
06117     return default_inspect(self, "WIN32OLE_TYPE");
06118 }
06119 
06120 static VALUE
06121 ole_variables(ITypeInfo *pTypeInfo)
06122 {
06123     HRESULT hr;
06124     TYPEATTR *pTypeAttr;
06125     WORD i;
06126     UINT len;
06127     BSTR bstr;
06128     VARDESC *pVarDesc;
06129     struct olevariabledata *pvar;
06130     VALUE var;
06131     VALUE variables = rb_ary_new();
06132     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
06133     if (FAILED(hr)) {
06134         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetTypeAttr");
06135     }
06136 
06137     for(i = 0; i < pTypeAttr->cVars; i++) {
06138         hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, i, &pVarDesc);
06139         if(FAILED(hr))
06140             continue;
06141         len = 0;
06142         hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
06143                                          1, &len);
06144         if(FAILED(hr) || len == 0 || !bstr)
06145             continue;
06146 
06147         var = Data_Make_Struct(cWIN32OLE_VARIABLE, struct olevariabledata,
06148                                0,olevariable_free,pvar);
06149         pvar->pTypeInfo = pTypeInfo;
06150         OLE_ADDREF(pTypeInfo);
06151         pvar->index = i;
06152         rb_ivar_set(var, rb_intern("name"), WC2VSTR(bstr));
06153         rb_ary_push(variables, var);
06154 
06155         pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06156         pVarDesc = NULL;
06157     }
06158     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
06159     return variables;
06160 }
06161 
06162 /*
06163  *  call-seq:
06164  *     WIN32OLE_TYPE#variables
06165  *
06166  *  Returns array of WIN32OLE_VARIABLE objects which represent variables
06167  *  defined in OLE class.
06168  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06169  *     vars = tobj.variables
06170  *     vars.each do |v|
06171  *       puts "#{v.name} = #{v.value}"
06172  *     end
06173  *
06174  *     The result of above sample script is follows:
06175  *       xlChart = -4109
06176  *       xlDialogSheet = -4116
06177  *       xlExcel4IntlMacroSheet = 4
06178  *       xlExcel4MacroSheet = 3
06179  *       xlWorksheet = -4167
06180  *
06181  */
06182 static VALUE
06183 foletype_variables(VALUE self)
06184 {
06185     struct oletypedata *ptype;
06186     Data_Get_Struct(self, struct oletypedata, ptype);
06187     return ole_variables(ptype->pTypeInfo);
06188 }
06189 
06190 /*
06191  *  call-seq:
06192  *     WIN32OLE_TYPE#ole_methods # the array of WIN32OLE_METHOD objects.
06193  *
06194  *  Returns array of WIN32OLE_METHOD objects which represent OLE method defined in
06195  *  OLE type library.
06196  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
06197  *    methods = tobj.ole_methods.collect{|m|
06198  *      m.name
06199  *    }
06200  *    # => ['Activate', 'Copy', 'Delete',....]
06201  */
06202 static VALUE
06203 foletype_methods(VALUE self)
06204 {
06205     struct oletypedata *ptype;
06206     Data_Get_Struct(self, struct oletypedata, ptype);
06207     return ole_methods_from_typeinfo(ptype->pTypeInfo, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
06208 }
06209 
06210 /*
06211  * Document-class: WIN32OLE_VARIABLE
06212  *
06213  *   <code>WIN32OLE_VARIABLE</code> objects represent OLE variable information.
06214  */
06215 
06216 /*
06217  *  call-seq:
06218  *     WIN32OLE_VARIABLE#name
06219  *
06220  *  Returns the name of variable.
06221  *
06222  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06223  *     variables = tobj.variables
06224  *     variables.each do |variable|
06225  *       puts "#{variable.name}"
06226  *     end
06227  *
06228  *     The result of above script is following:
06229  *       xlChart
06230  *       xlDialogSheet
06231  *       xlExcel4IntlMacroSheet
06232  *       xlExcel4MacroSheet
06233  *       xlWorksheet
06234  *
06235  */
06236 static VALUE
06237 folevariable_name(VALUE self)
06238 {
06239     return rb_ivar_get(self, rb_intern("name"));
06240 }
06241 
06242 static VALUE
06243 ole_variable_ole_type(ITypeInfo *pTypeInfo, UINT var_index)
06244 {
06245     VARDESC *pVarDesc;
06246     HRESULT hr;
06247     VALUE type;
06248     hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
06249     if (FAILED(hr))
06250         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetVarDesc");
06251     type = ole_typedesc2val(pTypeInfo, &(pVarDesc->elemdescVar.tdesc), Qnil);
06252     pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06253     return type;
06254 }
06255 
06256 /*
06257  *   call-seq:
06258  *      WIN32OLE_VARIABLE#ole_type
06259  *
06260  *   Returns OLE type string.
06261  *
06262  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06263  *     variables = tobj.variables
06264  *     variables.each do |variable|
06265  *       puts "#{variable.ole_type} #{variable.name}"
06266  *     end
06267  *
06268  *     The result of above script is following:
06269  *       INT xlChart
06270  *       INT xlDialogSheet
06271  *       INT xlExcel4IntlMacroSheet
06272  *       INT xlExcel4MacroSheet
06273  *       INT xlWorksheet
06274  *
06275  */
06276 static VALUE
06277 folevariable_ole_type(VALUE self)
06278 {
06279     struct olevariabledata *pvar;
06280     Data_Get_Struct(self, struct olevariabledata, pvar);
06281     return ole_variable_ole_type(pvar->pTypeInfo, pvar->index);
06282 }
06283 
06284 static VALUE
06285 ole_variable_ole_type_detail(ITypeInfo *pTypeInfo, UINT var_index)
06286 {
06287     VARDESC *pVarDesc;
06288     HRESULT hr;
06289     VALUE type = rb_ary_new();
06290     hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
06291     if (FAILED(hr))
06292         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetVarDesc");
06293     ole_typedesc2val(pTypeInfo, &(pVarDesc->elemdescVar.tdesc), type);
06294     pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06295     return type;
06296 }
06297 
06298 /*
06299  *  call-seq:
06300  *     WIN32OLE_VARIABLE#ole_type_detail
06301  *
06302  *  Returns detail information of type. The information is array of type.
06303  *
06304  *     tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library', 'D3DCLIPSTATUS')
06305  *     variable = tobj.variables.find {|variable| variable.name == 'lFlags'}
06306  *     tdetail  = variable.ole_type_detail
06307  *     p tdetail # => ["USERDEFINED", "CONST_D3DCLIPSTATUSFLAGS"]
06308  *
06309  */
06310 static VALUE
06311 folevariable_ole_type_detail(VALUE self)
06312 {
06313     struct olevariabledata *pvar;
06314     Data_Get_Struct(self, struct olevariabledata, pvar);
06315     return ole_variable_ole_type_detail(pvar->pTypeInfo, pvar->index);
06316 }
06317 
06318 static VALUE
06319 ole_variable_value(ITypeInfo *pTypeInfo, UINT var_index)
06320 {
06321     VARDESC *pVarDesc;
06322     HRESULT hr;
06323     VALUE val = Qnil;
06324     hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
06325     if (FAILED(hr))
06326         return Qnil;
06327     if(pVarDesc->varkind == VAR_CONST)
06328         val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
06329     pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06330     return val;
06331 }
06332 
06333 /*
06334  *  call-seq:
06335  *     WIN32OLE_VARIABLE#value
06336  *
06337  *  Returns value if value is exists. If the value does not exist,
06338  *  this method returns nil.
06339  *
06340  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06341  *     variables = tobj.variables
06342  *     variables.each do |variable|
06343  *       puts "#{variable.name} #{variable.value}"
06344  *     end
06345  *
06346  *     The result of above script is following:
06347  *       xlChart = -4109
06348  *       xlDialogSheet = -4116
06349  *       xlExcel4IntlMacroSheet = 4
06350  *       xlExcel4MacroSheet = 3
06351  *       xlWorksheet = -4167
06352  *
06353  */
06354 static VALUE
06355 folevariable_value(VALUE self)
06356 {
06357     struct olevariabledata *pvar;
06358     Data_Get_Struct(self, struct olevariabledata, pvar);
06359     return ole_variable_value(pvar->pTypeInfo, pvar->index);
06360 }
06361 
06362 static VALUE
06363 ole_variable_visible(ITypeInfo *pTypeInfo, UINT var_index)
06364 {
06365     VARDESC *pVarDesc;
06366     HRESULT hr;
06367     VALUE visible = Qfalse;
06368     hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
06369     if (FAILED(hr))
06370         return visible;
06371     if (!(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
06372                                  VARFLAG_FRESTRICTED |
06373                                  VARFLAG_FNONBROWSABLE))) {
06374         visible = Qtrue;
06375     }
06376     pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06377     return visible;
06378 }
06379 
06380 /*
06381  *  call-seq:
06382  *     WIN32OLE_VARIABLE#visible?
06383  *
06384  *  Returns true if the variable is public.
06385  *
06386  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06387  *     variables = tobj.variables
06388  *     variables.each do |variable|
06389  *       puts "#{variable.name} #{variable.visible?}"
06390  *     end
06391  *
06392  *     The result of above script is following:
06393  *       xlChart true
06394  *       xlDialogSheet true
06395  *       xlExcel4IntlMacroSheet true
06396  *       xlExcel4MacroSheet true
06397  *       xlWorksheet true
06398  *
06399  */
06400 static VALUE
06401 folevariable_visible(VALUE self)
06402 {
06403     struct olevariabledata *pvar;
06404     Data_Get_Struct(self, struct olevariabledata, pvar);
06405     return ole_variable_visible(pvar->pTypeInfo, pvar->index);
06406 }
06407 
06408 static VALUE
06409 ole_variable_kind(ITypeInfo *pTypeInfo, UINT var_index)
06410 {
06411     VARDESC *pVarDesc;
06412     HRESULT hr;
06413     VALUE kind = rb_str_new2("UNKNOWN");
06414     hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
06415     if (FAILED(hr))
06416         return kind;
06417     switch(pVarDesc->varkind) {
06418     case VAR_PERINSTANCE:
06419         kind = rb_str_new2("PERINSTANCE");
06420         break;
06421     case VAR_STATIC:
06422         kind = rb_str_new2("STATIC");
06423         break;
06424     case VAR_CONST:
06425         kind = rb_str_new2("CONSTANT");
06426         break;
06427     case VAR_DISPATCH:
06428         kind = rb_str_new2("DISPATCH");
06429         break;
06430     default:
06431         break;
06432     }
06433     pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06434     return kind;
06435 }
06436 
06437 /*
06438  * call-seq:
06439  *   WIN32OLE_VARIABLE#variable_kind
06440  *
06441  * Returns variable kind string.
06442  *
06443  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06444  *    variables = tobj.variables
06445  *    variables.each do |variable|
06446  *      puts "#{variable.name} #{variable.variable_kind}"
06447  *    end
06448  *
06449  *    The result of above script is following:
06450  *      xlChart CONSTANT
06451  *      xlDialogSheet CONSTANT
06452  *      xlExcel4IntlMacroSheet CONSTANT
06453  *      xlExcel4MacroSheet CONSTANT
06454  *      xlWorksheet CONSTANT
06455  */
06456 static VALUE
06457 folevariable_variable_kind(VALUE self)
06458 {
06459     struct olevariabledata *pvar;
06460     Data_Get_Struct(self, struct olevariabledata, pvar);
06461     return ole_variable_kind(pvar->pTypeInfo, pvar->index);
06462 }
06463 
06464 static VALUE
06465 ole_variable_varkind(ITypeInfo *pTypeInfo, UINT var_index)
06466 {
06467     VARDESC *pVarDesc;
06468     HRESULT hr;
06469     VALUE kind = Qnil;
06470     hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
06471     if (FAILED(hr))
06472         return kind;
06473     pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
06474     kind = INT2FIX(pVarDesc->varkind);
06475     return kind;
06476 }
06477 
06478 /*
06479  *  call-seq:
06480  *     WIN32OLE_VARIABLE#varkind
06481  *
06482  *  Returns the number which represents variable kind.
06483  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
06484  *    variables = tobj.variables
06485  *    variables.each do |variable|
06486  *      puts "#{variable.name} #{variable.varkind}"
06487  *    end
06488  *
06489  *    The result of above script is following:
06490  *       xlChart 2
06491  *       xlDialogSheet 2
06492  *       xlExcel4IntlMacroSheet 2
06493  *       xlExcel4MacroSheet 2
06494  *       xlWorksheet 2
06495  */
06496 static VALUE
06497 folevariable_varkind(VALUE self)
06498 {
06499     struct olevariabledata *pvar;
06500     Data_Get_Struct(self, struct olevariabledata, pvar);
06501     return ole_variable_varkind(pvar->pTypeInfo, pvar->index);
06502 }
06503 
06504 /*
06505  *  call-seq:
06506  *     WIN32OLE_VARIABLE#inspect -> String
06507  *
06508  *  Returns the OLE variable name and the value with class name.
06509  *
06510  */
06511 static VALUE
06512 folevariable_inspect(VALUE self)
06513 {
06514     VALUE detail = rb_funcall(self, rb_intern("to_s"), 0);
06515     rb_str_cat2(detail, "=");
06516     rb_str_concat(detail, rb_funcall(rb_funcall(self, rb_intern("value"), 0), rb_intern("inspect"), 0));
06517     return make_inspect("WIN32OLE_VARIABLE", detail);
06518 }
06519 
06520 /*
06521  * Document-class: WIN32OLE_METHOD
06522  *
06523  *   <code>WIN32OLE_METHOD</code> objects represent OLE method information.
06524  */
06525 
06526 static VALUE
06527 olemethod_set_member(VALUE self, ITypeInfo *pTypeInfo, ITypeInfo *pOwnerTypeInfo, int index, VALUE name)
06528 {
06529     struct olemethoddata *pmethod;
06530     Data_Get_Struct(self, struct olemethoddata, pmethod);
06531     pmethod->pTypeInfo = pTypeInfo;
06532     OLE_ADDREF(pTypeInfo);
06533     pmethod->pOwnerTypeInfo = pOwnerTypeInfo;
06534     if(pOwnerTypeInfo) OLE_ADDREF(pOwnerTypeInfo);
06535     pmethod->index = index;
06536     rb_ivar_set(self, rb_intern("name"), name);
06537     return self;
06538 }
06539 
06540 static VALUE
06541 folemethod_s_allocate(VALUE klass)
06542 {
06543     struct olemethoddata *pmethod;
06544     VALUE obj;
06545     obj = Data_Make_Struct(klass,
06546                            struct olemethoddata,
06547                            0, olemethod_free, pmethod);
06548     pmethod->pTypeInfo = NULL;
06549     pmethod->pOwnerTypeInfo = NULL;
06550     pmethod->index = 0;
06551     return obj;
06552 }
06553 
06554 /*
06555  *  call-seq:
06556  *     WIN32OLE_METHOD.new(ole_type,  method) -> WIN32OLE_METHOD object
06557  *
06558  *  Returns a new WIN32OLE_METHOD object which represents the information
06559  *  about OLE method.
06560  *  The first argument <i>ole_type</i> specifies WIN32OLE_TYPE object.
06561  *  The second argument <i>method</i> specifies OLE method name defined OLE class
06562  *  which represents WIN32OLE_TYPE object.
06563  *
06564  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
06565  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
06566  */
06567 static VALUE
06568 folemethod_initialize(VALUE self, VALUE oletype, VALUE method)
06569 {
06570     struct oletypedata *ptype;
06571     VALUE obj = Qnil;
06572     if (rb_obj_is_kind_of(oletype, cWIN32OLE_TYPE)) {
06573         SafeStringValue(method);
06574         Data_Get_Struct(oletype, struct oletypedata, ptype);
06575         obj = olemethod_from_typeinfo(self, ptype->pTypeInfo, method);
06576         if (obj == Qnil) {
06577             rb_raise(eWIN32OLERuntimeError, "not found %s",
06578                      StringValuePtr(method));
06579         }
06580     }
06581     else {
06582         rb_raise(rb_eTypeError, "1st argument should be WIN32OLE_TYPE object");
06583     }
06584     return obj;
06585 }
06586 
06587 /*
06588  *  call-seq
06589  *     WIN32OLE_METHOD#name
06590  *
06591  *  Returns the name of the method.
06592  *
06593  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
06594  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
06595  *     puts method.name # => SaveAs
06596  *
06597  */
06598 static VALUE
06599 folemethod_name(VALUE self)
06600 {
06601     return rb_ivar_get(self, rb_intern("name"));
06602 }
06603 
06604 static VALUE
06605 ole_method_return_type(ITypeInfo *pTypeInfo, UINT method_index)
06606 {
06607     FUNCDESC *pFuncDesc;
06608     HRESULT hr;
06609     VALUE type;
06610 
06611     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
06612     if (FAILED(hr))
06613         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetFuncDesc");
06614 
06615     type = ole_typedesc2val(pTypeInfo, &(pFuncDesc->elemdescFunc.tdesc), Qnil);
06616     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
06617     return type;
06618 }
06619 
06620 /*
06621  *  call-seq:
06622  *     WIN32OLE_METHOD#return_type
06623  *
06624  *  Returns string of return value type of method.
06625  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06626  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06627  *     puts method.return_type # => Workbook
06628  *
06629  */
06630 static VALUE
06631 folemethod_return_type(VALUE self)
06632 {
06633     struct olemethoddata *pmethod;
06634     Data_Get_Struct(self, struct olemethoddata, pmethod);
06635     return ole_method_return_type(pmethod->pTypeInfo, pmethod->index);
06636 }
06637 
06638 static VALUE
06639 ole_method_return_vtype(ITypeInfo *pTypeInfo, UINT method_index)
06640 {
06641     FUNCDESC *pFuncDesc;
06642     HRESULT hr;
06643     VALUE vvt;
06644 
06645     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
06646     if (FAILED(hr))
06647         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetFuncDesc");
06648 
06649     vvt = INT2FIX(pFuncDesc->elemdescFunc.tdesc.vt);
06650     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
06651     return vvt;
06652 }
06653 
06654 /*
06655  *  call-seq:
06656  *     WIN32OLE_METHOD#return_vtype
06657  *
06658  *  Returns number of return value type of method.
06659  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06660  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06661  *     puts method.return_vtype # => 26
06662  *
06663  */
06664 static VALUE
06665 folemethod_return_vtype(VALUE self)
06666 {
06667     struct olemethoddata *pmethod;
06668     Data_Get_Struct(self, struct olemethoddata, pmethod);
06669     return ole_method_return_vtype(pmethod->pTypeInfo, pmethod->index);
06670 }
06671 
06672 static VALUE
06673 ole_method_return_type_detail(ITypeInfo *pTypeInfo, UINT method_index)
06674 {
06675     FUNCDESC *pFuncDesc;
06676     HRESULT hr;
06677     VALUE type = rb_ary_new();
06678 
06679     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
06680     if (FAILED(hr))
06681         return type;
06682 
06683     ole_typedesc2val(pTypeInfo, &(pFuncDesc->elemdescFunc.tdesc), type);
06684     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
06685     return type;
06686 }
06687 
06688 /*
06689  *  call-seq:
06690  *     WIN32OLE_METHOD#return_type_detail
06691  *
06692  *  Returns detail information of return value type of method.
06693  *  The information is array.
06694  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06695  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06696  *     p method.return_type_detail # => ["PTR", "USERDEFINED", "Workbook"]
06697  */
06698 static VALUE
06699 folemethod_return_type_detail(VALUE self)
06700 {
06701     struct olemethoddata *pmethod;
06702     Data_Get_Struct(self, struct olemethoddata, pmethod);
06703     return ole_method_return_type_detail(pmethod->pTypeInfo, pmethod->index);
06704 }
06705 
06706 static VALUE
06707 ole_method_invkind(ITypeInfo *pTypeInfo, UINT method_index)
06708 {
06709     FUNCDESC *pFuncDesc;
06710     HRESULT hr;
06711     VALUE invkind;
06712     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
06713     if(FAILED(hr))
06714         ole_raise(hr, eWIN32OLERuntimeError, "failed to GetFuncDesc");
06715     invkind = INT2FIX(pFuncDesc->invkind);
06716     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
06717     return invkind;
06718 }
06719 
06720 static VALUE
06721 ole_method_invoke_kind(ITypeInfo *pTypeInfo, UINT method_index)
06722 {
06723     VALUE type = rb_str_new2("UNKNOWN");
06724     VALUE invkind = ole_method_invkind(pTypeInfo, method_index);
06725     if((FIX2INT(invkind) & INVOKE_PROPERTYGET) &&
06726        (FIX2INT(invkind) & INVOKE_PROPERTYPUT) ) {
06727         type = rb_str_new2("PROPERTY");
06728     } else if(FIX2INT(invkind) & INVOKE_PROPERTYGET) {
06729         type =  rb_str_new2("PROPERTYGET");
06730     } else if(FIX2INT(invkind) & INVOKE_PROPERTYPUT) {
06731         type = rb_str_new2("PROPERTYPUT");
06732     } else if(FIX2INT(invkind) & INVOKE_PROPERTYPUTREF) {
06733         type = rb_str_new2("PROPERTYPUTREF");
06734     } else if(FIX2INT(invkind) & INVOKE_FUNC) {
06735         type = rb_str_new2("FUNC");
06736     }
06737     return type;
06738 }
06739 
06740 /*
06741  *   call-seq:
06742  *      WIN32OLE_MTHOD#invkind
06743  *
06744  *   Returns the method invoke kind.
06745  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06746  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06747  *     puts method.invkind # => 1
06748  *
06749  */
06750 static VALUE
06751 folemethod_invkind(VALUE self)
06752 {
06753     struct olemethoddata *pmethod;
06754     Data_Get_Struct(self, struct olemethoddata, pmethod);
06755     return ole_method_invkind(pmethod->pTypeInfo, pmethod->index);
06756 }
06757 
06758 /*
06759  *  call-seq:
06760  *     WIN32OLE_METHOD#invoke_kind
06761  *
06762  *  Returns the method kind string. The string is "UNKNOWN" or "PROPERTY"
06763  *  or "PROPERTY" or "PROPERTYGET" or "PROPERTYPUT" or "PROPERTYPPUTREF"
06764  *  or "FUNC".
06765  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06766  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06767  *     puts method.invoke_kind # => "FUNC"
06768  */
06769 static VALUE
06770 folemethod_invoke_kind(VALUE self)
06771 {
06772     struct olemethoddata *pmethod;
06773     Data_Get_Struct(self, struct olemethoddata, pmethod);
06774     return ole_method_invoke_kind(pmethod->pTypeInfo, pmethod->index);
06775 }
06776 
06777 static VALUE
06778 ole_method_visible(ITypeInfo *pTypeInfo, UINT method_index)
06779 {
06780     FUNCDESC *pFuncDesc;
06781     HRESULT hr;
06782     VALUE visible;
06783     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
06784     if(FAILED(hr))
06785         return Qfalse;
06786     if (pFuncDesc->wFuncFlags & (FUNCFLAG_FRESTRICTED |
06787                                  FUNCFLAG_FHIDDEN |
06788                                  FUNCFLAG_FNONBROWSABLE)) {
06789         visible = Qfalse;
06790     } else {
06791         visible = Qtrue;
06792     }
06793     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
06794     return visible;
06795 }
06796 
06797 /*
06798  *  call-seq:
06799  *     WIN32OLE_METHOD#visible?
06800  *
06801  *  Returns true if the method is public.
06802  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06803  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06804  *     puts method.visible? # => true
06805  */
06806 static VALUE
06807 folemethod_visible(VALUE self)
06808 {
06809     struct olemethoddata *pmethod;
06810     Data_Get_Struct(self, struct olemethoddata, pmethod);
06811     return ole_method_visible(pmethod->pTypeInfo, pmethod->index);
06812 }
06813 
06814 static VALUE
06815 ole_method_event(ITypeInfo *pTypeInfo, UINT method_index, VALUE method_name)
06816 {
06817     TYPEATTR *pTypeAttr;
06818     HRESULT hr;
06819     WORD i;
06820     int flags;
06821     HREFTYPE href;
06822     ITypeInfo *pRefTypeInfo;
06823     FUNCDESC *pFuncDesc;
06824     BSTR bstr;
06825     VALUE name;
06826     VALUE event = Qfalse;
06827 
06828     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
06829     if (FAILED(hr))
06830         return event;
06831     if(pTypeAttr->typekind != TKIND_COCLASS) {
06832         pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
06833         return event;
06834     }
06835     for (i = 0; i < pTypeAttr->cImplTypes; i++) {
06836         hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
06837         if (FAILED(hr))
06838             continue;
06839 
06840         if (flags & IMPLTYPEFLAG_FSOURCE) {
06841             hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
06842                                                          i, &href);
06843             if (FAILED(hr))
06844                 continue;
06845             hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
06846                                                    href, &pRefTypeInfo);
06847             if (FAILED(hr))
06848                 continue;
06849             hr = pRefTypeInfo->lpVtbl->GetFuncDesc(pRefTypeInfo, method_index,
06850                                                    &pFuncDesc);
06851             if (FAILED(hr)) {
06852                 OLE_RELEASE(pRefTypeInfo);
06853                 continue;
06854             }
06855 
06856             hr = pRefTypeInfo->lpVtbl->GetDocumentation(pRefTypeInfo,
06857                                                         pFuncDesc->memid,
06858                                                         &bstr, NULL, NULL, NULL);
06859             if (FAILED(hr)) {
06860                 pRefTypeInfo->lpVtbl->ReleaseFuncDesc(pRefTypeInfo, pFuncDesc);
06861                 OLE_RELEASE(pRefTypeInfo);
06862                 continue;
06863             }
06864 
06865             name = WC2VSTR(bstr);
06866             pRefTypeInfo->lpVtbl->ReleaseFuncDesc(pRefTypeInfo, pFuncDesc);
06867             OLE_RELEASE(pRefTypeInfo);
06868             if (rb_str_cmp(method_name, name) == 0) {
06869                 event = Qtrue;
06870                 break;
06871             }
06872         }
06873     }
06874     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
06875     return event;
06876 }
06877 
06878 /*
06879  *  call-seq:
06880  *     WIN32OLE_METHOD#event?
06881  *
06882  *  Returns true if the method is event.
06883  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
06884  *     method = WIN32OLE_METHOD.new(tobj, 'SheetActivate')
06885  *     puts method.event? # => true
06886  *
06887  */
06888 static VALUE
06889 folemethod_event(VALUE self)
06890 {
06891     struct olemethoddata *pmethod;
06892     Data_Get_Struct(self, struct olemethoddata, pmethod);
06893     if (!pmethod->pOwnerTypeInfo)
06894         return Qfalse;
06895     return ole_method_event(pmethod->pOwnerTypeInfo,
06896                             pmethod->index,
06897                             rb_ivar_get(self, rb_intern("name")));
06898 }
06899 
06900 /*
06901  *  call-seq:
06902  *     WIN32OLE_METHOD#event_interface
06903  *
06904  *  Returns event interface name if the method is event.
06905  *    tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
06906  *    method = WIN32OLE_METHOD.new(tobj, 'SheetActivate')
06907  *    puts method.event_interface # =>  WorkbookEvents
06908  */
06909 static VALUE
06910 folemethod_event_interface(VALUE self)
06911 {
06912     BSTR name;
06913     struct olemethoddata *pmethod;
06914     HRESULT hr;
06915     Data_Get_Struct(self, struct olemethoddata, pmethod);
06916     if(folemethod_event(self) == Qtrue) {
06917         hr = ole_docinfo_from_type(pmethod->pTypeInfo, &name, NULL, NULL, NULL);
06918         if(SUCCEEDED(hr))
06919             return WC2VSTR(name);
06920     }
06921     return Qnil;
06922 }
06923 
06924 static VALUE
06925 ole_method_docinfo_from_type(
06926     ITypeInfo *pTypeInfo,
06927     UINT method_index,
06928     BSTR *name,
06929     BSTR *helpstr,
06930     DWORD *helpcontext,
06931     BSTR *helpfile
06932     )
06933 {
06934     FUNCDESC *pFuncDesc;
06935     HRESULT hr;
06936     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
06937     if (FAILED(hr))
06938         return hr;
06939     hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
06940                                              name, helpstr,
06941                                              helpcontext, helpfile);
06942     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
06943     return hr;
06944 }
06945 
06946 static VALUE
06947 ole_method_helpstring(ITypeInfo *pTypeInfo, UINT method_index)
06948 {
06949     HRESULT hr;
06950     BSTR bhelpstring;
06951     hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, &bhelpstring,
06952                                       NULL, NULL);
06953     if (FAILED(hr))
06954         return Qnil;
06955     return WC2VSTR(bhelpstring);
06956 }
06957 
06958 /*
06959  *  call-seq:
06960  *     WIN32OLE_METHOD#helpstring
06961  *
06962  *  Returns help string of OLE method. If the help string is not found,
06963  *  then the method returns nil.
06964  *     tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'IWebBrowser')
06965  *     method = WIN32OLE_METHOD.new(tobj, 'Navigate')
06966  *     puts method.helpstring # => Navigates to a URL or file.
06967  *
06968  */
06969 static VALUE
06970 folemethod_helpstring(VALUE self)
06971 {
06972     struct olemethoddata *pmethod;
06973     Data_Get_Struct(self, struct olemethoddata, pmethod);
06974     return ole_method_helpstring(pmethod->pTypeInfo, pmethod->index);
06975 }
06976 
06977 static VALUE
06978 ole_method_helpfile(ITypeInfo *pTypeInfo, UINT method_index)
06979 {
06980     HRESULT hr;
06981     BSTR bhelpfile;
06982     hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, NULL,
06983                                       NULL, &bhelpfile);
06984     if (FAILED(hr))
06985         return Qnil;
06986     return WC2VSTR(bhelpfile);
06987 }
06988 
06989 /*
06990  *  call-seq:
06991  *     WIN32OLE_METHOD#helpfile
06992  *
06993  *  Returns help file. If help file is not found, then
06994  *  the method returns nil.
06995  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
06996  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
06997  *     puts method.helpfile # => C:\...\VBAXL9.CHM
06998  */
06999 static VALUE
07000 folemethod_helpfile(VALUE self)
07001 {
07002     struct olemethoddata *pmethod;
07003     Data_Get_Struct(self, struct olemethoddata, pmethod);
07004 
07005     return ole_method_helpfile(pmethod->pTypeInfo, pmethod->index);
07006 }
07007 
07008 static VALUE
07009 ole_method_helpcontext(ITypeInfo *pTypeInfo, UINT method_index)
07010 {
07011     HRESULT hr;
07012     DWORD helpcontext = 0;
07013     hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, NULL,
07014                                       &helpcontext, NULL);
07015     if (FAILED(hr))
07016         return Qnil;
07017     return INT2FIX(helpcontext);
07018 }
07019 
07020 /*
07021  *  call-seq:
07022  *     WIN32OLE_METHOD#helpcontext
07023  *
07024  *  Returns help context.
07025  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
07026  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
07027  *     puts method.helpcontext # => 65717
07028  */
07029 static VALUE
07030 folemethod_helpcontext(VALUE self)
07031 {
07032     struct olemethoddata *pmethod;
07033     Data_Get_Struct(self, struct olemethoddata, pmethod);
07034     return ole_method_helpcontext(pmethod->pTypeInfo, pmethod->index);
07035 }
07036 
07037 static VALUE
07038 ole_method_dispid(ITypeInfo *pTypeInfo, UINT method_index)
07039 {
07040     FUNCDESC *pFuncDesc;
07041     HRESULT hr;
07042     VALUE dispid = Qnil;
07043     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07044     if (FAILED(hr))
07045         return dispid;
07046     dispid = INT2NUM(pFuncDesc->memid);
07047     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07048     return dispid;
07049 }
07050 
07051 /*
07052  *  call-seq:
07053  *     WIN32OLE_METHOD#dispid
07054  *
07055  *  Returns dispatch ID.
07056  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
07057  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
07058  *     puts method.dispid # => 181
07059  */
07060 static VALUE
07061 folemethod_dispid(VALUE self)
07062 {
07063     struct olemethoddata *pmethod;
07064     Data_Get_Struct(self, struct olemethoddata, pmethod);
07065     return ole_method_dispid(pmethod->pTypeInfo, pmethod->index);
07066 }
07067 
07068 static VALUE
07069 ole_method_offset_vtbl(ITypeInfo *pTypeInfo, UINT method_index)
07070 {
07071     FUNCDESC *pFuncDesc;
07072     HRESULT hr;
07073     VALUE offset_vtbl = Qnil;
07074     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07075     if (FAILED(hr))
07076         return offset_vtbl;
07077     offset_vtbl = INT2FIX(pFuncDesc->oVft);
07078     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07079     return offset_vtbl;
07080 }
07081 
07082 /*
07083  *  call-seq:
07084  *     WIN32OLE_METHOD#offset_vtbl
07085  *
07086  *  Returns the offset ov VTBL.
07087  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
07088  *     method = WIN32OLE_METHOD.new(tobj, 'Add')
07089  *     puts method.offset_vtbl # => 40
07090  */
07091 static VALUE
07092 folemethod_offset_vtbl(VALUE self)
07093 {
07094     struct olemethoddata *pmethod;
07095     Data_Get_Struct(self, struct olemethoddata, pmethod);
07096     return ole_method_offset_vtbl(pmethod->pTypeInfo, pmethod->index);
07097 }
07098 
07099 static VALUE
07100 ole_method_size_params(ITypeInfo *pTypeInfo, UINT method_index)
07101 {
07102     FUNCDESC *pFuncDesc;
07103     HRESULT hr;
07104     VALUE size_params = Qnil;
07105     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07106     if (FAILED(hr))
07107         return size_params;
07108     size_params = INT2FIX(pFuncDesc->cParams);
07109     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07110     return size_params;
07111 }
07112 
07113 /*
07114  *  call-seq:
07115  *     WIN32OLE_METHOD#size_params
07116  *
07117  *  Returns the size of arguments of the method.
07118  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07119  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07120  *     puts method.size_params # => 11
07121  *
07122  */
07123 static VALUE
07124 folemethod_size_params(VALUE self)
07125 {
07126     struct olemethoddata *pmethod;
07127     Data_Get_Struct(self, struct olemethoddata, pmethod);
07128     return ole_method_size_params(pmethod->pTypeInfo, pmethod->index);
07129 }
07130 
07131 static VALUE
07132 ole_method_size_opt_params(ITypeInfo *pTypeInfo, UINT method_index)
07133 {
07134     FUNCDESC *pFuncDesc;
07135     HRESULT hr;
07136     VALUE size_opt_params = Qnil;
07137     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07138     if (FAILED(hr))
07139         return size_opt_params;
07140     size_opt_params = INT2FIX(pFuncDesc->cParamsOpt);
07141     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07142     return size_opt_params;
07143 }
07144 
07145 /*
07146  *  call-seq:
07147  *     WIN32OLE_METHOD#size_opt_params
07148  *
07149  *  Returns the size of optional parameters.
07150  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07151  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07152  *     puts method.size_opt_params # => 4
07153  */
07154 static VALUE
07155 folemethod_size_opt_params(VALUE self)
07156 {
07157     struct olemethoddata *pmethod;
07158     Data_Get_Struct(self, struct olemethoddata, pmethod);
07159     return ole_method_size_opt_params(pmethod->pTypeInfo, pmethod->index);
07160 }
07161 
07162 static VALUE
07163 ole_method_params(ITypeInfo *pTypeInfo, UINT method_index)
07164 {
07165     FUNCDESC *pFuncDesc;
07166     HRESULT hr;
07167     BSTR *bstrs;
07168     UINT len, i;
07169     struct oleparamdata *pparam;
07170     VALUE param;
07171     VALUE params = rb_ary_new();
07172     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07173     if (FAILED(hr))
07174         return params;
07175 
07176     len = 0;
07177     bstrs = ALLOCA_N(BSTR, pFuncDesc->cParams + 1);
07178     hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pFuncDesc->memid,
07179                                      bstrs, pFuncDesc->cParams + 1,
07180                                      &len);
07181     if (FAILED(hr)) {
07182         pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07183         return params;
07184     }
07185     SysFreeString(bstrs[0]);
07186     if (pFuncDesc->cParams > 0) {
07187         for(i = 1; i < len; i++) {
07188             param = Data_Make_Struct(cWIN32OLE_PARAM, struct oleparamdata, 0,
07189                                      oleparam_free, pparam);
07190             pparam->pTypeInfo = pTypeInfo;
07191             OLE_ADDREF(pTypeInfo);
07192             pparam->method_index = method_index;
07193             pparam->index = i - 1;
07194             rb_ivar_set(param, rb_intern("name"), WC2VSTR(bstrs[i]));
07195             rb_ary_push(params, param);
07196          }
07197      }
07198      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07199      return params;
07200 }
07201 
07202 
07203 /*
07204  *  call-seq:
07205  *     WIN32OLE_METHOD#params
07206  *
07207  *  returns array of WIN32OLE_PARAM object corresponding with method parameters.
07208  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07209  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07210  *     p method.params # => [Filename, FileFormat, Password, WriteResPassword,
07211  *                           ReadOnlyRecommended, CreateBackup, AccessMode,
07212  *                           ConflictResolution, AddToMru, TextCodepage,
07213  *                           TextVisualLayout]
07214  */
07215 static VALUE
07216 folemethod_params(VALUE self)
07217 {
07218     struct olemethoddata *pmethod;
07219     Data_Get_Struct(self, struct olemethoddata, pmethod);
07220     return ole_method_params(pmethod->pTypeInfo, pmethod->index);
07221 }
07222 
07223 /*
07224  *  call-seq:
07225  *     WIN32OLE_METHOD#inspect -> String
07226  *
07227  *  Returns the method name with class name.
07228  *
07229  */
07230 static VALUE
07231 folemethod_inspect(VALUE self)
07232 {
07233     return default_inspect(self, "WIN32OLE_METHOD");
07234 }
07235 
07236 /*
07237  * Document-class: WIN32OLE_PARAM
07238  *
07239  *   <code>WIN32OLE_PARAM</code> objects represent param information of
07240  *   the OLE method.
07241  */
07242 static VALUE foleparam_s_allocate(VALUE klass)
07243 {
07244     struct oleparamdata *pparam;
07245     VALUE obj;
07246     obj = Data_Make_Struct(klass,
07247                            struct oleparamdata,
07248                            0, oleparam_free, pparam);
07249     pparam->pTypeInfo = NULL;
07250     pparam->method_index = 0;
07251     pparam->index = 0;
07252     return obj;
07253 }
07254 
07255 static VALUE
07256 oleparam_ole_param_from_index(VALUE self, ITypeInfo *pTypeInfo, UINT method_index, int param_index)
07257 {
07258     FUNCDESC *pFuncDesc;
07259     HRESULT hr;
07260     BSTR *bstrs;
07261     UINT len;
07262     struct oleparamdata *pparam;
07263     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07264     if (FAILED(hr))
07265         ole_raise(hr, rb_eRuntimeError, "fail to ITypeInfo::GetFuncDesc");
07266 
07267     len = 0;
07268     bstrs = ALLOCA_N(BSTR, pFuncDesc->cParams + 1);
07269     hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pFuncDesc->memid,
07270                                      bstrs, pFuncDesc->cParams + 1,
07271                                      &len);
07272     if (FAILED(hr)) {
07273         pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07274         ole_raise(hr, rb_eRuntimeError, "fail to ITypeInfo::GetNames");
07275     }
07276     SysFreeString(bstrs[0]);
07277     if (param_index < 1 || len <= (UINT)param_index)
07278     {
07279         pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07280         rb_raise(rb_eIndexError, "index of param must be in 1..%d", len);
07281     }
07282 
07283     Data_Get_Struct(self, struct oleparamdata, pparam);
07284     pparam->pTypeInfo = pTypeInfo;
07285     OLE_ADDREF(pTypeInfo);
07286     pparam->method_index = method_index;
07287     pparam->index = param_index - 1;
07288     rb_ivar_set(self, rb_intern("name"), WC2VSTR(bstrs[param_index]));
07289 
07290     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07291     return self;
07292 }
07293 
07294 static VALUE oleparam_ole_param(VALUE self, VALUE olemethod, int n)
07295 {
07296     struct olemethoddata *pmethod;
07297     Data_Get_Struct(olemethod, struct olemethoddata, pmethod);
07298     return oleparam_ole_param_from_index(self, pmethod->pTypeInfo, pmethod->index, n);
07299 }
07300 
07301 static VALUE foleparam_initialize(VALUE self, VALUE olemethod, VALUE n)
07302 {
07303     int idx;
07304     if (!rb_obj_is_kind_of(olemethod, cWIN32OLE_METHOD)) {
07305         rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE_METHOD object");
07306     }
07307     idx = FIX2INT(n);
07308     return oleparam_ole_param(self, olemethod, idx);
07309 }
07310 
07311 /*
07312  *  call-seq:
07313  *     WIN32OLE_PARAM#name
07314  *
07315  *  Returns name.
07316  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07317  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07318  *     param1 = method.params[0]
07319  *     puts param1.name # => Filename
07320  */
07321 static VALUE
07322 foleparam_name(VALUE self)
07323 {
07324     return rb_ivar_get(self, rb_intern("name"));
07325 }
07326 
07327 static VALUE
07328 ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
07329 {
07330     FUNCDESC *pFuncDesc;
07331     HRESULT hr;
07332     VALUE type = rb_str_new2("unknown type");
07333     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07334     if (FAILED(hr))
07335         return type;
07336     type = ole_typedesc2val(pTypeInfo,
07337                             &(pFuncDesc->lprgelemdescParam[index].tdesc), Qnil);
07338     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07339     return type;
07340 }
07341 
07342 /*
07343  *  call-seq:
07344  *     WIN32OLE_PARAM#ole_type
07345  *
07346  *  Returns OLE type of WIN32OLE_PARAM object(parameter of OLE method).
07347  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07348  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07349  *     param1 = method.params[0]
07350  *     puts param1.ole_type # => VARIANT
07351  */
07352 static VALUE
07353 foleparam_ole_type(VALUE self)
07354 {
07355     struct oleparamdata *pparam;
07356     Data_Get_Struct(self, struct oleparamdata, pparam);
07357     return ole_param_ole_type(pparam->pTypeInfo, pparam->method_index,
07358                               pparam->index);
07359 }
07360 
07361 static VALUE
07362 ole_param_ole_type_detail(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
07363 {
07364     FUNCDESC *pFuncDesc;
07365     HRESULT hr;
07366     VALUE typedetail = rb_ary_new();
07367     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07368     if (FAILED(hr))
07369         return typedetail;
07370     ole_typedesc2val(pTypeInfo,
07371                      &(pFuncDesc->lprgelemdescParam[index].tdesc), typedetail);
07372     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07373     return typedetail;
07374 }
07375 
07376 /*
07377  *  call-seq:
07378  *     WIN32OLE_PARAM#ole_type_detail
07379  *
07380  *  Returns detail information of type of argument.
07381  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'IWorksheetFunction')
07382  *     method = WIN32OLE_METHOD.new(tobj, 'SumIf')
07383  *     param1 = method.params[0]
07384  *     p param1.ole_type_detail # => ["PTR", "USERDEFINED", "Range"]
07385  */
07386 static VALUE
07387 foleparam_ole_type_detail(VALUE self)
07388 {
07389     struct oleparamdata *pparam;
07390     Data_Get_Struct(self, struct oleparamdata, pparam);
07391     return ole_param_ole_type_detail(pparam->pTypeInfo, pparam->method_index,
07392                                      pparam->index);
07393 }
07394 
07395 static VALUE
07396 ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT mask)
07397 {
07398     FUNCDESC *pFuncDesc;
07399     HRESULT hr;
07400     VALUE ret = Qfalse;
07401     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07402     if(FAILED(hr))
07403         return ret;
07404     if (V_UNION1((&(pFuncDesc->lprgelemdescParam[index])), paramdesc).wParamFlags &mask)
07405         ret = Qtrue;
07406     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07407     return ret;
07408 }
07409 
07410 /*
07411  *  call-seq:
07412  *     WIN32OLE_PARAM#input?
07413  *
07414  *  Returns true if the parameter is input.
07415  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07416  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07417  *     param1 = method.params[0]
07418  *     puts param1.input? # => true
07419  */
07420 static VALUE foleparam_input(VALUE self)
07421 {
07422     struct oleparamdata *pparam;
07423     Data_Get_Struct(self, struct oleparamdata, pparam);
07424     return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
07425                                pparam->index, PARAMFLAG_FIN);
07426 }
07427 
07428 /*
07429  *  call-seq:
07430  *     WIN32OLE#output?
07431  *
07432  *  Returns true if argument is output.
07433  *     tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'DWebBrowserEvents')
07434  *     method = WIN32OLE_METHOD.new(tobj, 'NewWindow')
07435  *     method.params.each do |param|
07436  *       puts "#{param.name} #{param.output?}"
07437  *     end
07438  *
07439  *     The result of above script is following:
07440  *       URL false
07441  *       Flags false
07442  *       TargetFrameName false
07443  *       PostData false
07444  *       Headers false
07445  *       Processed true
07446  */
07447 static VALUE foleparam_output(VALUE self)
07448 {
07449     struct oleparamdata *pparam;
07450     Data_Get_Struct(self, struct oleparamdata, pparam);
07451     return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
07452                                pparam->index, PARAMFLAG_FOUT);
07453 }
07454 
07455 /*
07456  *  call-seq:
07457  *     WIN32OLE_PARAM#optional?
07458  *
07459  *  Returns true if argument is optional.
07460  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07461  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07462  *     param1 = method.params[0]
07463  *     puts "#{param1.name} #{param1.optional?}" # => Filename true
07464  */
07465 static VALUE foleparam_optional(VALUE self)
07466 {
07467     struct oleparamdata *pparam;
07468     Data_Get_Struct(self, struct oleparamdata, pparam);
07469     return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
07470                                pparam->index, PARAMFLAG_FOPT);
07471 }
07472 
07473 /*
07474  *  call-seq:
07475  *     WIN32OLE_PARAM#retval?
07476  *
07477  *  Returns true if argument is return value.
07478  *     tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library',
07479  *                              'DirectPlayLobbyConnection')
07480  *     method = WIN32OLE_METHOD.new(tobj, 'GetPlayerShortName')
07481  *     param = method.params[0]
07482  *     puts "#{param.name} #{param.retval?}"  # => name true
07483  */
07484 static VALUE foleparam_retval(VALUE self)
07485 {
07486     struct oleparamdata *pparam;
07487     Data_Get_Struct(self, struct oleparamdata, pparam);
07488     return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index,
07489                                pparam->index, PARAMFLAG_FRETVAL);
07490 }
07491 
07492 static VALUE
07493 ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
07494 {
07495     FUNCDESC *pFuncDesc;
07496     ELEMDESC *pElemDesc;
07497     PARAMDESCEX * pParamDescEx;
07498     HRESULT hr;
07499     USHORT wParamFlags;
07500     USHORT mask = PARAMFLAG_FOPT|PARAMFLAG_FHASDEFAULT;
07501     VALUE defval = Qnil;
07502     hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
07503     if (FAILED(hr))
07504         return defval;
07505     pElemDesc = &pFuncDesc->lprgelemdescParam[index];
07506     wParamFlags = V_UNION1(pElemDesc, paramdesc).wParamFlags;
07507     if ((wParamFlags & mask) == mask) {
07508          pParamDescEx = V_UNION1(pElemDesc, paramdesc).pparamdescex;
07509          defval = ole_variant2val(&pParamDescEx->varDefaultValue);
07510     }
07511     pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
07512     return defval;
07513 }
07514 
07515 /*
07516  *  call-seq:
07517  *     WIN32OLE_PARAM#default
07518  *
07519  *  Returns default value. If the default value does not exist,
07520  *  this method returns nil.
07521  *     tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
07522  *     method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
07523  *     method.params.each do |param|
07524  *       if param.default
07525  *         puts "#{param.name} (= #{param.default})"
07526  *       else
07527  *         puts "#{param}"
07528  *       end
07529  *     end
07530  *
07531  *     The above script result is following:
07532  *         Filename
07533  *         FileFormat
07534  *         Password
07535  *         WriteResPassword
07536  *         ReadOnlyRecommended
07537  *         CreateBackup
07538  *         AccessMode (= 1)
07539  *         ConflictResolution
07540  *         AddToMru
07541  *         TextCodepage
07542  *         TextVisualLayout
07543  */
07544 static VALUE foleparam_default(VALUE self)
07545 {
07546     struct oleparamdata *pparam;
07547     Data_Get_Struct(self, struct oleparamdata, pparam);
07548     return ole_param_default(pparam->pTypeInfo, pparam->method_index,
07549                              pparam->index);
07550 }
07551 
07552 /*
07553  *  call-seq:
07554  *     WIN32OLE_PARAM#inspect -> String
07555  *
07556  *  Returns the parameter name with class name. If the parameter has default value,
07557  *  then returns name=value string with class name.
07558  *
07559  */
07560 static VALUE
07561 foleparam_inspect(VALUE self)
07562 {
07563     VALUE detail = foleparam_name(self);
07564     VALUE defval = foleparam_default(self);
07565     if (defval != Qnil) {
07566         rb_str_cat2(detail, "=");
07567         rb_str_concat(detail, rb_funcall(defval, rb_intern("inspect"), 0));
07568     }
07569     return make_inspect("WIN32OLE_PARAM", detail);
07570 }
07571 
07572 /*
07573  * Document-class: WIN32OLE_EVENT
07574  *
07575  *   <code>WIN32OLE_EVENT</code> objects controls OLE event.
07576  */
07577 
07578 static IEventSinkVtbl vtEventSink;
07579 static BOOL g_IsEventSinkVtblInitialized = FALSE;
07580 
07581 void EVENTSINK_Destructor(PIEVENTSINKOBJ);
07582 
07583 STDMETHODIMP
07584 EVENTSINK_QueryInterface(
07585     PEVENTSINK pEV,
07586     REFIID     iid,
07587     LPVOID*    ppv
07588     ) {
07589     if (IsEqualIID(iid, &IID_IUnknown) ||
07590         IsEqualIID(iid, &IID_IDispatch) ||
07591         IsEqualIID(iid, &((PIEVENTSINKOBJ)pEV)->m_iid)) {
07592         *ppv = pEV;
07593     }
07594     else {
07595         *ppv = NULL;
07596         return E_NOINTERFACE;
07597     }
07598     ((LPUNKNOWN)*ppv)->lpVtbl->AddRef((LPUNKNOWN)*ppv);
07599     return NOERROR;
07600 }
07601 
07602 STDMETHODIMP_(ULONG)
07603 EVENTSINK_AddRef(
07604     PEVENTSINK pEV
07605     ){
07606     PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
07607     return ++pEVObj->m_cRef;
07608 }
07609 
07610 STDMETHODIMP_(ULONG) EVENTSINK_Release(
07611     PEVENTSINK pEV
07612     ) {
07613     PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
07614     --pEVObj->m_cRef;
07615     if(pEVObj->m_cRef != 0)
07616         return pEVObj->m_cRef;
07617     EVENTSINK_Destructor(pEVObj);
07618     return 0;
07619 }
07620 
07621 STDMETHODIMP EVENTSINK_GetTypeInfoCount(
07622     PEVENTSINK pEV,
07623     UINT *pct
07624     ) {
07625     *pct = 0;
07626     return NOERROR;
07627 }
07628 
07629 STDMETHODIMP EVENTSINK_GetTypeInfo(
07630     PEVENTSINK pEV,
07631     UINT info,
07632     LCID lcid,
07633     ITypeInfo **pInfo
07634     ) {
07635     *pInfo = NULL;
07636     return DISP_E_BADINDEX;
07637 }
07638 
07639 STDMETHODIMP EVENTSINK_GetIDsOfNames(
07640     PEVENTSINK pEventSink,
07641     REFIID riid,
07642     OLECHAR **szNames,
07643     UINT cNames,
07644     LCID lcid,
07645     DISPID *pDispID
07646     ) {
07647     ITypeInfo *pTypeInfo;
07648     PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
07649     pTypeInfo = pEV->pTypeInfo;
07650     if (pTypeInfo) {
07651         return pTypeInfo->lpVtbl->GetIDsOfNames(pTypeInfo, szNames, cNames, pDispID);
07652     }
07653     return DISP_E_UNKNOWNNAME;
07654 }
07655 
07656 static long
07657 ole_search_event_at(VALUE ary, VALUE ev)
07658 {
07659     VALUE event;
07660     VALUE event_name;
07661     long i, len;
07662     long ret = -1;
07663     len = RARRAY_LEN(ary);
07664     for(i = 0; i < len; i++) {
07665         event = rb_ary_entry(ary, i);
07666         event_name = rb_ary_entry(event, 1);
07667         if(NIL_P(event_name) && NIL_P(ev)) {
07668             ret = i;
07669             break;
07670         }
07671         else if (TYPE(ev) == T_STRING &&
07672                  TYPE(event_name) == T_STRING &&
07673                  rb_str_cmp(ev, event_name) == 0) {
07674             ret = i;
07675             break;
07676         }
07677     }
07678     return ret;
07679 }
07680 
07681 static VALUE
07682 ole_search_event(VALUE ary, VALUE ev, BOOL  *is_default)
07683 {
07684     VALUE event;
07685     VALUE def_event;
07686     VALUE event_name;
07687     int i, len;
07688     *is_default = FALSE;
07689     def_event = Qnil;
07690     len = RARRAY_LEN(ary);
07691     for(i = 0; i < len; i++) {
07692         event = rb_ary_entry(ary, i);
07693         event_name = rb_ary_entry(event, 1);
07694         if(NIL_P(event_name)) {
07695             *is_default = TRUE;
07696             def_event = event;
07697         }
07698         else if (rb_str_cmp(ev, event_name) == 0) {
07699             *is_default = FALSE;
07700             return event;
07701         }
07702     }
07703     return def_event;
07704 }
07705 static VALUE
07706 ole_search_handler_method(VALUE handler, VALUE ev, BOOL *is_default_handler)
07707 {
07708     VALUE mid;
07709 
07710     *is_default_handler = FALSE;
07711     mid = rb_to_id(rb_sprintf("on%s", StringValuePtr(ev)));
07712     if (rb_respond_to(handler, mid)) {
07713         return mid;
07714     }
07715     mid = rb_intern("method_missing");
07716     if (rb_respond_to(handler, mid)) {
07717         *is_default_handler = TRUE;
07718         return mid;
07719     }
07720     return Qnil;
07721 }
07722 
07723 static void
07724 ole_delete_event(VALUE ary, VALUE ev)
07725 {
07726     long at = -1;
07727     at = ole_search_event_at(ary, ev);
07728     if (at >= 0) {
07729         rb_ary_delete_at(ary, at);
07730     }
07731 }
07732 
07733 static void
07734 hash2ptr_dispparams(VALUE hash, ITypeInfo *pTypeInfo, DISPID dispid, DISPPARAMS *pdispparams)
07735 {
07736     BSTR *bstrs;
07737     HRESULT hr;
07738     UINT len, i;
07739     VARIANT *pvar;
07740     VALUE val;
07741     VALUE key;
07742     len = 0;
07743     bstrs = ALLOCA_N(BSTR, pdispparams->cArgs + 1);
07744     hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
07745                                      bstrs, pdispparams->cArgs + 1,
07746                                      &len);
07747     if (FAILED(hr))
07748         return;
07749 
07750     for (i = 0; i < len - 1; i++) {
07751         key = WC2VSTR(bstrs[i + 1]);
07752         val = rb_hash_aref(hash, INT2FIX(i));
07753         if (val == Qnil)
07754             val = rb_hash_aref(hash, key);
07755         if (val == Qnil)
07756             val = rb_hash_aref(hash, rb_str_intern(key));
07757         pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
07758         ole_val2ptr_variant(val, pvar);
07759     }
07760 }
07761 
07762 static VALUE
07763 hash2result(VALUE hash)
07764 {
07765     VALUE ret = Qnil;
07766     ret = rb_hash_aref(hash, rb_str_new2("return"));
07767     if (ret == Qnil)
07768         ret = rb_hash_aref(hash, rb_str_intern(rb_str_new2("return")));
07769     return ret;
07770 }
07771 
07772 static void
07773 ary2ptr_dispparams(VALUE ary, DISPPARAMS *pdispparams)
07774 {
07775     int i;
07776     VALUE v;
07777     VARIANT *pvar;
07778     for(i = 0; i < RARRAY_LEN(ary) && (unsigned int) i < pdispparams->cArgs; i++) {
07779         v = rb_ary_entry(ary, i);
07780         pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
07781         ole_val2ptr_variant(v, pvar);
07782     }
07783 }
07784 
07785 static VALUE
07786 exec_callback(VALUE arg)
07787 {
07788     VALUE *parg = (VALUE *)arg;
07789     VALUE handler = parg[0];
07790     VALUE mid = parg[1];
07791     VALUE args = parg[2];
07792     return rb_apply(handler, mid, args);
07793 }
07794 
07795 static VALUE
07796 rescue_callback(VALUE arg)
07797 {
07798 
07799     VALUE error;
07800     VALUE e = rb_errinfo();
07801     VALUE bt = rb_funcall(e, rb_intern("backtrace"), 0);
07802     VALUE msg = rb_funcall(e, rb_intern("message"), 0);
07803     bt = rb_ary_entry(bt, 0);
07804     error = rb_sprintf("%s: %s (%s)\n", StringValuePtr(bt), StringValuePtr(msg), rb_obj_classname(e));
07805     rb_write_error(StringValuePtr(error));
07806     rb_backtrace();
07807     ruby_finalize();
07808     exit(-1);
07809 
07810     return Qnil;
07811 }
07812 
07813 STDMETHODIMP EVENTSINK_Invoke(
07814     PEVENTSINK pEventSink,
07815     DISPID dispid,
07816     REFIID riid,
07817     LCID lcid,
07818     WORD wFlags,
07819     DISPPARAMS *pdispparams,
07820     VARIANT *pvarResult,
07821     EXCEPINFO *pexcepinfo,
07822     UINT *puArgErr
07823     ) {
07824 
07825     HRESULT hr;
07826     BSTR bstr;
07827     unsigned int count;
07828     unsigned int i;
07829     ITypeInfo *pTypeInfo;
07830     VARIANT *pvar;
07831     VALUE ary, obj, event, args, outargv, ev, result;
07832     VALUE handler = Qnil;
07833     VALUE arg[3];
07834     VALUE mid;
07835     VALUE is_outarg = Qfalse;
07836     BOOL is_default_handler = FALSE;
07837     int state;
07838 
07839     PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
07840     pTypeInfo = pEV->pTypeInfo;
07841     obj = evs_entry(pEV->m_event_id);
07842     if (!rb_obj_is_kind_of(obj, cWIN32OLE_EVENT)) {
07843         return NOERROR;
07844     }
07845 
07846     ary = rb_ivar_get(obj, id_events);
07847     if (NIL_P(ary) || TYPE(ary) != T_ARRAY) {
07848         return NOERROR;
07849     }
07850     hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
07851                                      &bstr, 1, &count);
07852     if (FAILED(hr)) {
07853         return NOERROR;
07854     }
07855     ev = WC2VSTR(bstr);
07856     event = ole_search_event(ary, ev, &is_default_handler);
07857     if (TYPE(event) == T_ARRAY) {
07858         handler = rb_ary_entry(event, 0);
07859         mid = rb_intern("call");
07860         is_outarg = rb_ary_entry(event, 3);
07861     } else {
07862         handler = rb_ivar_get(obj, rb_intern("handler"));
07863         if (handler == Qnil) {
07864             return NOERROR;
07865         }
07866         mid = ole_search_handler_method(handler, ev, &is_default_handler);
07867     }
07868     if (handler == Qnil || mid == Qnil) {
07869         return NOERROR;
07870     }
07871 
07872     args = rb_ary_new();
07873     if (is_default_handler) {
07874         rb_ary_push(args, ev);
07875     }
07876 
07877     /* make argument of event handler */
07878     for (i = 0; i < pdispparams->cArgs; ++i) {
07879         pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
07880         rb_ary_push(args, ole_variant2val(pvar));
07881     }
07882     outargv = Qnil;
07883     if (is_outarg == Qtrue) {
07884         outargv = rb_ary_new();
07885         rb_ary_push(args, outargv);
07886     }
07887 
07888     /*
07889      * if exception raised in event callback,
07890      * then you receive cfp consistency error.
07891      * to avoid this error we use begin rescue end.
07892      * and the exception raised then error message print
07893      * and exit ruby process by Win32OLE itself.
07894      */
07895     arg[0] = handler;
07896     arg[1] = mid;
07897     arg[2] = args;
07898     result = rb_protect(exec_callback, (VALUE)arg, &state);
07899     if (state != 0) {
07900         rescue_callback(Qnil);
07901     }
07902     if(TYPE(result) == T_HASH) {
07903         hash2ptr_dispparams(result, pTypeInfo, dispid, pdispparams);
07904         result = hash2result(result);
07905     }else if (is_outarg == Qtrue && TYPE(outargv) == T_ARRAY) {
07906         ary2ptr_dispparams(outargv, pdispparams);
07907     }
07908 
07909     if (pvarResult) {
07910         VariantInit(pvarResult);
07911         ole_val2variant(result, pvarResult);
07912     }
07913 
07914     return NOERROR;
07915 }
07916 
07917 PIEVENTSINKOBJ
07918 EVENTSINK_Constructor() {
07919     PIEVENTSINKOBJ pEv;
07920     if (!g_IsEventSinkVtblInitialized) {
07921         vtEventSink.QueryInterface=EVENTSINK_QueryInterface;
07922         vtEventSink.AddRef = EVENTSINK_AddRef;
07923         vtEventSink.Release = EVENTSINK_Release;
07924         vtEventSink.Invoke = EVENTSINK_Invoke;
07925         vtEventSink.GetIDsOfNames = EVENTSINK_GetIDsOfNames;
07926         vtEventSink.GetTypeInfoCount = EVENTSINK_GetTypeInfoCount;
07927         vtEventSink.GetTypeInfo = EVENTSINK_GetTypeInfo;
07928 
07929         g_IsEventSinkVtblInitialized = TRUE;
07930     }
07931     pEv = ALLOC_N(IEVENTSINKOBJ, 1);
07932     if(pEv == NULL) return NULL;
07933     pEv->lpVtbl = &vtEventSink;
07934     pEv->m_cRef = 0;
07935     pEv->m_event_id = 0;
07936     pEv->pTypeInfo = NULL;
07937     return pEv;
07938 }
07939 
07940 void EVENTSINK_Destructor(
07941     PIEVENTSINKOBJ pEVObj
07942     ) {
07943     if(pEVObj != NULL) {
07944         OLE_RELEASE(pEVObj->pTypeInfo);
07945         free(pEVObj);
07946         pEVObj = NULL;
07947     }
07948 }
07949 
07950 static HRESULT
07951 find_iid(VALUE ole, char *pitf, IID *piid, ITypeInfo **ppTypeInfo)
07952 {
07953     HRESULT hr;
07954     IDispatch *pDispatch;
07955     ITypeInfo *pTypeInfo;
07956     ITypeLib *pTypeLib;
07957     TYPEATTR *pTypeAttr;
07958     HREFTYPE RefType;
07959     ITypeInfo *pImplTypeInfo;
07960     TYPEATTR *pImplTypeAttr;
07961 
07962     struct oledata *pole;
07963     unsigned int index;
07964     unsigned int count;
07965     int type;
07966     BSTR bstr;
07967     char *pstr;
07968 
07969     BOOL is_found = FALSE;
07970     LCID    lcid = cWIN32OLE_lcid;
07971 
07972     OLEData_Get_Struct(ole, pole);
07973 
07974     pDispatch = pole->pDispatch;
07975 
07976     hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo);
07977     if (FAILED(hr))
07978         return hr;
07979 
07980     hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo,
07981                                                  &pTypeLib,
07982                                                  &index);
07983     OLE_RELEASE(pTypeInfo);
07984     if (FAILED(hr))
07985         return hr;
07986 
07987     if (!pitf) {
07988         hr = pTypeLib->lpVtbl->GetTypeInfoOfGuid(pTypeLib,
07989                                                  piid,
07990                                                  ppTypeInfo);
07991         OLE_RELEASE(pTypeLib);
07992         return hr;
07993     }
07994     count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
07995     for (index = 0; index < count; index++) {
07996         hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib,
07997                                            index,
07998                                            &pTypeInfo);
07999         if (FAILED(hr))
08000             break;
08001         hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
08002 
08003         if(FAILED(hr)) {
08004             OLE_RELEASE(pTypeInfo);
08005             break;
08006         }
08007         if(pTypeAttr->typekind == TKIND_COCLASS) {
08008             for (type = 0; type < pTypeAttr->cImplTypes; type++) {
08009                 hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
08010                                                              type,
08011                                                              &RefType);
08012                 if (FAILED(hr))
08013                     break;
08014                 hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
08015                                                        RefType,
08016                                                        &pImplTypeInfo);
08017                 if (FAILED(hr))
08018                     break;
08019 
08020                 hr = pImplTypeInfo->lpVtbl->GetDocumentation(pImplTypeInfo,
08021                                                              -1,
08022                                                              &bstr,
08023                                                              NULL, NULL, NULL);
08024                 if (FAILED(hr)) {
08025                     OLE_RELEASE(pImplTypeInfo);
08026                     break;
08027                 }
08028                 pstr = ole_wc2mb(bstr);
08029                 if (strcmp(pitf, pstr) == 0) {
08030                     hr = pImplTypeInfo->lpVtbl->GetTypeAttr(pImplTypeInfo,
08031                                                             &pImplTypeAttr);
08032                     if (SUCCEEDED(hr)) {
08033                         is_found = TRUE;
08034                         *piid = pImplTypeAttr->guid;
08035                         if (ppTypeInfo) {
08036                             *ppTypeInfo = pImplTypeInfo;
08037                             (*ppTypeInfo)->lpVtbl->AddRef((*ppTypeInfo));
08038                         }
08039                         pImplTypeInfo->lpVtbl->ReleaseTypeAttr(pImplTypeInfo,
08040                                                                pImplTypeAttr);
08041                     }
08042                 }
08043                 free(pstr);
08044                 OLE_RELEASE(pImplTypeInfo);
08045                 if (is_found || FAILED(hr))
08046                     break;
08047             }
08048         }
08049 
08050         OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
08051         OLE_RELEASE(pTypeInfo);
08052         if (is_found || FAILED(hr))
08053             break;
08054     }
08055     OLE_RELEASE(pTypeLib);
08056     if(!is_found)
08057         return E_NOINTERFACE;
08058     return hr;
08059 }
08060 
08061 static HRESULT
08062 find_coclass(
08063     ITypeInfo *pTypeInfo,
08064     TYPEATTR *pTypeAttr,
08065     ITypeInfo **pCOTypeInfo,
08066     TYPEATTR **pCOTypeAttr)
08067 {
08068     HRESULT hr = E_NOINTERFACE;
08069     ITypeLib *pTypeLib;
08070     int count;
08071     BOOL found = FALSE;
08072     ITypeInfo *pTypeInfo2;
08073     TYPEATTR *pTypeAttr2;
08074     int flags;
08075     int i,j;
08076     HREFTYPE href;
08077     ITypeInfo *pRefTypeInfo;
08078     TYPEATTR *pRefTypeAttr;
08079 
08080     hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, NULL);
08081     if (FAILED(hr)) {
08082         return hr;
08083     }
08084     count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
08085     for (i = 0; i < count && !found; i++) {
08086         hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo2);
08087         if (FAILED(hr))
08088             continue;
08089         hr = OLE_GET_TYPEATTR(pTypeInfo2, &pTypeAttr2);
08090         if (FAILED(hr)) {
08091             OLE_RELEASE(pTypeInfo2);
08092             continue;
08093         }
08094         if (pTypeAttr2->typekind != TKIND_COCLASS) {
08095             OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
08096             OLE_RELEASE(pTypeInfo2);
08097             continue;
08098         }
08099         for (j = 0; j < pTypeAttr2->cImplTypes && !found; j++) {
08100             hr = pTypeInfo2->lpVtbl->GetImplTypeFlags(pTypeInfo2, j, &flags);
08101             if (FAILED(hr))
08102                 continue;
08103             if (!(flags & IMPLTYPEFLAG_FDEFAULT))
08104                 continue;
08105             hr = pTypeInfo2->lpVtbl->GetRefTypeOfImplType(pTypeInfo2, j, &href);
08106             if (FAILED(hr))
08107                 continue;
08108             hr = pTypeInfo2->lpVtbl->GetRefTypeInfo(pTypeInfo2, href, &pRefTypeInfo);
08109             if (FAILED(hr))
08110                 continue;
08111             hr = OLE_GET_TYPEATTR(pRefTypeInfo, &pRefTypeAttr);
08112             if (FAILED(hr))  {
08113                 OLE_RELEASE(pRefTypeInfo);
08114                 continue;
08115             }
08116             if (IsEqualGUID(&(pTypeAttr->guid), &(pRefTypeAttr->guid))) {
08117                 found = TRUE;
08118             }
08119         }
08120         if (!found) {
08121             OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
08122             OLE_RELEASE(pTypeInfo2);
08123         }
08124     }
08125     OLE_RELEASE(pTypeLib);
08126     if (found) {
08127         *pCOTypeInfo = pTypeInfo2;
08128         *pCOTypeAttr = pTypeAttr2;
08129         hr = S_OK;
08130     } else {
08131         hr = E_NOINTERFACE;
08132     }
08133     return hr;
08134 }
08135 
08136 static HRESULT
08137 find_default_source_from_typeinfo(
08138     ITypeInfo *pTypeInfo,
08139     TYPEATTR *pTypeAttr,
08140     ITypeInfo **ppTypeInfo)
08141 {
08142     int i = 0;
08143     HRESULT hr = E_NOINTERFACE;
08144     int flags;
08145     HREFTYPE hRefType;
08146     /* Enumerate all implemented types of the COCLASS */
08147     for (i = 0; i < pTypeAttr->cImplTypes; i++) {
08148         hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
08149         if (FAILED(hr))
08150             continue;
08151 
08152         /*
08153            looking for the [default] [source]
08154            we just hope that it is a dispinterface :-)
08155         */
08156         if ((flags & IMPLTYPEFLAG_FDEFAULT) &&
08157             (flags & IMPLTYPEFLAG_FSOURCE)) {
08158 
08159             hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
08160                                                          i, &hRefType);
08161             if (FAILED(hr))
08162                 continue;
08163             hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
08164                                                    hRefType, ppTypeInfo);
08165             if (SUCCEEDED(hr))
08166                 break;
08167         }
08168     }
08169     return hr;
08170 }
08171 
08172 static HRESULT
08173 find_default_source(VALUE ole, IID *piid, ITypeInfo **ppTypeInfo)
08174 {
08175     HRESULT hr;
08176     IProvideClassInfo2 *pProvideClassInfo2;
08177     IProvideClassInfo *pProvideClassInfo;
08178     void *p;
08179 
08180     IDispatch *pDispatch;
08181     ITypeInfo *pTypeInfo;
08182     ITypeInfo *pTypeInfo2 = NULL;
08183     TYPEATTR *pTypeAttr;
08184     TYPEATTR *pTypeAttr2 = NULL;
08185 
08186     struct oledata *pole;
08187 
08188     OLEData_Get_Struct(ole, pole);
08189     pDispatch = pole->pDispatch;
08190     hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
08191                                            &IID_IProvideClassInfo2,
08192                                            &p);
08193     if (SUCCEEDED(hr)) {
08194         pProvideClassInfo2 = p;
08195         hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2,
08196                                                  GUIDKIND_DEFAULT_SOURCE_DISP_IID,
08197                                                  piid);
08198         OLE_RELEASE(pProvideClassInfo2);
08199         if (SUCCEEDED(hr)) {
08200             hr = find_iid(ole, NULL, piid, ppTypeInfo);
08201         }
08202     }
08203     if (SUCCEEDED(hr)) {
08204         return hr;
08205     }
08206     hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
08207                                            &IID_IProvideClassInfo,
08208                                            &p);
08209     if (SUCCEEDED(hr)) {
08210         pProvideClassInfo = p;
08211         hr = pProvideClassInfo->lpVtbl->GetClassInfo(pProvideClassInfo,
08212                                                      &pTypeInfo);
08213         OLE_RELEASE(pProvideClassInfo);
08214     }
08215     if (FAILED(hr)) {
08216         hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, cWIN32OLE_lcid, &pTypeInfo );
08217     }
08218     if (FAILED(hr))
08219         return hr;
08220     hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
08221     if (FAILED(hr)) {
08222         OLE_RELEASE(pTypeInfo);
08223         return hr;
08224     }
08225 
08226     *ppTypeInfo = 0;
08227     hr = find_default_source_from_typeinfo(pTypeInfo, pTypeAttr, ppTypeInfo);
08228     if (!*ppTypeInfo) {
08229         hr = find_coclass(pTypeInfo, pTypeAttr, &pTypeInfo2, &pTypeAttr2);
08230         if (SUCCEEDED(hr)) {
08231             hr = find_default_source_from_typeinfo(pTypeInfo2, pTypeAttr2, ppTypeInfo);
08232             OLE_RELEASE_TYPEATTR(pTypeInfo2, pTypeAttr2);
08233             OLE_RELEASE(pTypeInfo2);
08234         }
08235     }
08236     OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
08237     OLE_RELEASE(pTypeInfo);
08238     /* Now that would be a bad surprise, if we didn't find it, wouldn't it? */
08239     if (!*ppTypeInfo) {
08240         if (SUCCEEDED(hr))
08241             hr = E_UNEXPECTED;
08242         return hr;
08243     }
08244 
08245     /* Determine IID of default source interface */
08246     hr = (*ppTypeInfo)->lpVtbl->GetTypeAttr(*ppTypeInfo, &pTypeAttr);
08247     if (SUCCEEDED(hr)) {
08248         *piid = pTypeAttr->guid;
08249         (*ppTypeInfo)->lpVtbl->ReleaseTypeAttr(*ppTypeInfo, pTypeAttr);
08250     }
08251     else
08252         OLE_RELEASE(*ppTypeInfo);
08253 
08254     return hr;
08255 
08256 }
08257 
08258 static void
08259 ole_event_free(struct oleeventdata *poleev)
08260 {
08261     if (poleev->pConnectionPoint) {
08262         poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie);
08263         OLE_RELEASE(poleev->pConnectionPoint);
08264         poleev->pConnectionPoint = NULL;
08265     }
08266     free(poleev);
08267 }
08268 
08269 static VALUE
08270 fev_s_allocate(VALUE klass)
08271 {
08272     VALUE obj;
08273     struct oleeventdata *poleev;
08274     obj = Data_Make_Struct(klass,struct oleeventdata,0,ole_event_free,poleev);
08275     poleev->dwCookie = 0;
08276     poleev->pConnectionPoint = NULL;
08277     poleev->event_id = 0;
08278     return obj;
08279 }
08280 
08281 static VALUE
08282 ev_advise(int argc, VALUE *argv, VALUE self)
08283 {
08284 
08285     VALUE ole, itf;
08286     struct oledata *pole;
08287     char *pitf;
08288     HRESULT hr;
08289     IID iid;
08290     ITypeInfo *pTypeInfo = 0;
08291     IDispatch *pDispatch;
08292     IConnectionPointContainer *pContainer;
08293     IConnectionPoint *pConnectionPoint;
08294     IEVENTSINKOBJ *pIEV;
08295     DWORD dwCookie;
08296     struct oleeventdata *poleev;
08297     void *p;
08298 
08299     rb_secure(4);
08300     rb_scan_args(argc, argv, "11", &ole, &itf);
08301 
08302     if (!rb_obj_is_kind_of(ole, cWIN32OLE)) {
08303         rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE object");
08304     }
08305 
08306     if(TYPE(itf) != T_NIL) {
08307         if (rb_safe_level() > 0 && OBJ_TAINTED(itf)) {
08308             rb_raise(rb_eSecurityError, "Insecure Event Creation - %s",
08309                      StringValuePtr(itf));
08310         }
08311         SafeStringValue(itf);
08312         pitf = StringValuePtr(itf);
08313         hr = find_iid(ole, pitf, &iid, &pTypeInfo);
08314     }
08315     else {
08316         hr = find_default_source(ole, &iid, &pTypeInfo);
08317     }
08318     if (FAILED(hr)) {
08319         ole_raise(hr, rb_eRuntimeError, "interface not found");
08320     }
08321 
08322     OLEData_Get_Struct(ole, pole);
08323     pDispatch = pole->pDispatch;
08324     hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
08325                                            &IID_IConnectionPointContainer,
08326                                            &p);
08327     if (FAILED(hr)) {
08328         OLE_RELEASE(pTypeInfo);
08329         ole_raise(hr, rb_eRuntimeError,
08330                   "failed to query IConnectionPointContainer");
08331     }
08332     pContainer = p;
08333 
08334     hr = pContainer->lpVtbl->FindConnectionPoint(pContainer,
08335                                                  &iid,
08336                                                  &pConnectionPoint);
08337     OLE_RELEASE(pContainer);
08338     if (FAILED(hr)) {
08339         OLE_RELEASE(pTypeInfo);
08340         ole_raise(hr, rb_eRuntimeError, "failed to query IConnectionPoint");
08341     }
08342     pIEV = EVENTSINK_Constructor();
08343     pIEV->m_iid = iid;
08344     hr = pConnectionPoint->lpVtbl->Advise(pConnectionPoint,
08345                                           (IUnknown*)pIEV,
08346                                           &dwCookie);
08347     if (FAILED(hr)) {
08348         ole_raise(hr, rb_eRuntimeError, "Advise Error");
08349     }
08350 
08351     Data_Get_Struct(self, struct oleeventdata, poleev);
08352     pIEV->m_event_id
08353         = NUM2INT(evs_length());
08354     pIEV->pTypeInfo = pTypeInfo;
08355     poleev->dwCookie = dwCookie;
08356     poleev->pConnectionPoint = pConnectionPoint;
08357     poleev->event_id = pIEV->m_event_id;
08358 
08359     return self;
08360 }
08361 
08362 /*
08363  *  call-seq:
08364  *     WIN32OLE_EVENT.new(ole, event) #=> WIN32OLE_EVENT object.
08365  *
08366  *  Returns OLE event object.
08367  *  The first argument specifies WIN32OLE object.
08368  *  The second argument specifies OLE event name.
08369  *     ie = WIN32OLE.new('InternetExplorer.Application')
08370  *     ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
08371  */
08372 static VALUE
08373 fev_initialize(int argc, VALUE *argv, VALUE self)
08374 {
08375     ev_advise(argc, argv, self);
08376     evs_push(self);
08377     rb_ivar_set(self, id_events, rb_ary_new());
08378     fev_set_handler(self, Qnil);
08379     return self;
08380 }
08381 
08382 /*
08383  *  call-seq:
08384  *     WIN32OLE_EVENT.message_loop
08385  *
08386  *  Translates and dispatches Windows message.
08387  */
08388 static VALUE
08389 fev_s_msg_loop(VALUE klass)
08390 {
08391     ole_msg_loop();
08392     return Qnil;
08393 }
08394 
08395 
08396 static void
08397 add_event_call_back(VALUE obj, VALUE event, VALUE data)
08398 {
08399     VALUE events = rb_ivar_get(obj, id_events);
08400     if (NIL_P(events) || TYPE(events) != T_ARRAY) {
08401         events = rb_ary_new();
08402         rb_ivar_set(obj, id_events, events);
08403     }
08404     ole_delete_event(events, event);
08405     rb_ary_push(events, data);
08406 }
08407 
08408 static VALUE
08409 ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
08410 {
08411     struct oleeventdata *poleev;
08412     VALUE event, args, data;
08413     Data_Get_Struct(self, struct oleeventdata, poleev);
08414     if (poleev->pConnectionPoint == NULL) {
08415         rb_raise(eWIN32OLERuntimeError, "IConnectionPoint not found. You must call advise at first.");
08416     }
08417     rb_scan_args(argc, argv, "01*", &event, &args);
08418     if(!NIL_P(event)) {
08419         if(TYPE(event) != T_STRING && TYPE(event) != T_SYMBOL) {
08420             rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
08421         }
08422         if (TYPE(event) == T_SYMBOL) {
08423             event = rb_sym_to_s(event);
08424         }
08425     }
08426     data = rb_ary_new3(4, rb_block_proc(), event, args, is_ary_arg);
08427     add_event_call_back(self, event, data);
08428     return Qnil;
08429 }
08430 
08431 /*
08432  *  call-seq:
08433  *     WIN32OLE_EVENT#on_event([event]){...}
08434  *
08435  *  Defines the callback event.
08436  *  If argument is omitted, this method defines the callback of all events.
08437  *  If you want to modify reference argument in callback, return hash in
08438  *  callback. If you want to return value to OLE server as result of callback
08439  *  use `return' or :return.
08440  *
08441  *    ie = WIN32OLE.new('InternetExplorer.Application')
08442  *    ev = WIN32OLE_EVENT.new(ie)
08443  *    ev.on_event("NavigateComplete") {|url| puts url}
08444  *    ev.on_event() {|ev, *args| puts "#{ev} fired"}
08445  *
08446  *    ev.on_event("BeforeNavigate2") {|*args|
08447  *      ...
08448  *      # set true to BeforeNavigate reference argument `Cancel'.
08449  *      # Cancel is 7-th argument of BeforeNavigate,
08450  *      # so you can use 6 as key of hash instead of 'Cancel'.
08451  *      # The argument is counted from 0.
08452  *      # The hash key of 0 means first argument.)
08453  *      {:Cancel => true}  # or {'Cancel' => true} or {6 => true}
08454  *    }
08455  *
08456  *    ev.on_event(...) {|*args|
08457  *      {:return => 1, :xxx => yyy}
08458  *    }
08459  */
08460 static VALUE
08461 fev_on_event(int argc, VALUE *argv, VALUE self)
08462 {
08463     return ev_on_event(argc, argv, self, Qfalse);
08464 }
08465 
08466 /*
08467  *  call-seq:
08468  *     WIN32OLE_EVENT#on_event_with_outargs([event]){...}
08469  *
08470  *  Defines the callback of event.
08471  *  If you want modify argument in callback,
08472  *  you could use this method instead of WIN32OLE_EVENT#on_event.
08473  *
08474  *    ie = WIN32OLE.new('InternetExplorer.Application')
08475  *    ev = WIN32OLE_EVENT.new(ie)
08476  *    ev.on_event_with_outargs('BeforeNavigate2') {|*args|
08477  *      args.last[6] = true
08478  *    }
08479  */
08480 static VALUE
08481 fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self)
08482 {
08483     return ev_on_event(argc, argv, self, Qtrue);
08484 }
08485 
08486 /*
08487  *  call-seq:
08488  *     WIN32OLE_EVENT#off_event([event])
08489  *
08490  *  removes the callback of event.
08491  *
08492  *    ie = WIN32OLE.new('InternetExplorer.Application')
08493  *    ev = WIN32OLE_EVENT.new(ie)
08494  *    ev.on_event('BeforeNavigate2') {|*args|
08495  *      args.last[6] = true
08496  *    }
08497  *      ...
08498  *    ev.off_event('BeforeNavigate2')
08499  *      ...
08500  */
08501 static VALUE
08502 fev_off_event(int argc, VALUE *argv, VALUE self)
08503 {
08504     VALUE event = Qnil;
08505     VALUE events;
08506 
08507     rb_secure(4);
08508     rb_scan_args(argc, argv, "01", &event);
08509     if(!NIL_P(event)) {
08510         if(TYPE(event) != T_STRING && TYPE(event) != T_SYMBOL) {
08511             rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
08512         }
08513         if (TYPE(event) == T_SYMBOL) {
08514             event = rb_sym_to_s(event);
08515         }
08516     }
08517     events = rb_ivar_get(self, id_events);
08518     if (NIL_P(events)) {
08519         return Qnil;
08520     }
08521     ole_delete_event(events, event);
08522     return Qnil;
08523 }
08524 
08525 /*
08526  *  call-seq:
08527  *     WIN32OLE_EVENT#unadvise -> nil
08528  *
08529  *  disconnects OLE server. If this method called, then the WIN32OLE_EVENT object
08530  *  does not receive the OLE server event any more.
08531  *  This method is trial implementation.
08532  *
08533  *      ie = WIN32OLE.new('InternetExplorer.Application')
08534  *      ev = WIN32OLE_EVENT.new(ie)
08535  *      ev.on_event() {...}
08536  *         ...
08537  *      ev.unadvise
08538  *
08539  */
08540 static VALUE
08541 fev_unadvise(VALUE self)
08542 {
08543     struct oleeventdata *poleev;
08544     Data_Get_Struct(self, struct oleeventdata, poleev);
08545     if (poleev->pConnectionPoint) {
08546         ole_msg_loop();
08547         evs_delete(poleev->event_id);
08548         poleev->pConnectionPoint->lpVtbl->Unadvise(poleev->pConnectionPoint, poleev->dwCookie);
08549         OLE_RELEASE(poleev->pConnectionPoint);
08550         poleev->pConnectionPoint = NULL;
08551     }
08552     return Qnil;
08553 }
08554 
08555 static VALUE
08556 evs_push(VALUE ev)
08557 {
08558     return rb_ary_push(ary_ole_event, ev);
08559 }
08560 
08561 static VALUE
08562 evs_delete(long i)
08563 {
08564     rb_ary_store(ary_ole_event, i, Qnil);
08565     return Qnil;
08566 }
08567 
08568 static VALUE
08569 evs_entry(long i)
08570 {
08571     return rb_ary_entry(ary_ole_event, i);
08572 }
08573 
08574 static VALUE
08575 evs_length(void)
08576 {
08577     return rb_funcall(ary_ole_event, rb_intern("length"), 0);
08578 }
08579 
08580 /*
08581  *  call-seq:
08582  *     WIN32OLE_EVENT#handler=
08583  *
08584  *  sets event handler object. If handler object has onXXX
08585  *  method according to XXX event, then onXXX method is called
08586  *  when XXX event occurs.
08587  *
08588  *  If handler object has method_missing and there is no
08589  *  method according to the event, then method_missing
08590  *  called and 1-st argument is event name.
08591  *
08592  *  If handler object has onXXX method and there is block
08593  *  defined by WIN32OLE_EVENT#on_event('XXX'){},
08594  *  then block is executed but handler object method is not called
08595  *  when XXX event occurs.
08596  *
08597  *      class Handler
08598  *        def onStatusTextChange(text)
08599  *          puts "StatusTextChanged"
08600  *        end
08601  *        def onPropertyChange(prop)
08602  *          puts "PropertyChanged"
08603  *        end
08604  *        def method_missing(ev, *arg)
08605  *          puts "other event #{ev}"
08606  *        end
08607  *      end
08608  *
08609  *      handler = Handler.new
08610  *      ie = WIN32OLE.new('InternetExplorer.Application')
08611  *      ev = WIN32OLE_EVENT.new(ie)
08612  *      ev.on_event("StatusTextChange") {|*args|
08613  *        puts "this block executed."
08614  *        puts "handler.onStatusTextChange method is not called."
08615  *      }
08616  *      ev.handler = handler
08617  *
08618  */
08619 static VALUE
08620 fev_set_handler(VALUE self, VALUE val)
08621 {
08622     return rb_ivar_set(self, rb_intern("handler"), val);
08623 }
08624 
08625 /*
08626  *  call-seq:
08627  *     WIN32OLE_EVENT#handler
08628  *
08629  *  returns handler object.
08630  *
08631  */
08632 static VALUE
08633 fev_get_handler(VALUE self)
08634 {
08635     return rb_ivar_get(self, rb_intern("handler"));
08636 }
08637 
08638 static void
08639 olevariant_free(struct olevariantdata *pvar)
08640 {
08641     VariantClear(&(pvar->realvar));
08642     VariantClear(&(pvar->var));
08643     free(pvar);
08644 }
08645 
08646 static VALUE
08647 folevariant_s_allocate(VALUE klass)
08648 {
08649     struct olevariantdata *pvar;
08650     VALUE obj;
08651     ole_initialize();
08652     obj = Data_Make_Struct(klass,struct olevariantdata,0,olevariant_free,pvar);
08653     VariantInit(&(pvar->var));
08654     VariantInit(&(pvar->realvar));
08655     return obj;
08656 }
08657 
08658 /*
08659  *  call-seq:
08660  *     WIN32OLE_VARIANT.array(ary, vt)
08661  *
08662  *  Returns Ruby object wrapping OLE variant whose variant type is VT_ARRAY.
08663  *  The first argument should be Array object which specifies dimensions
08664  *  and each size of dimensions of OLE array.
08665  *  The second argument specifies variant type of the element of OLE array.
08666  *
08667  *  The following create 2 dimensions OLE array. The first dimensions size
08668  *  is 3, and the second is 4.
08669  *
08670  *     ole_ary = WIN32OLE_VARIANT.array([3,4], VT_I4)
08671  *     ruby_ary = ole_ary.value # => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
08672  *
08673  */
08674 static VALUE
08675 folevariant_s_array(VALUE klass, VALUE elems, VALUE vvt)
08676 {
08677     VALUE obj = Qnil;
08678     VARTYPE vt;
08679     struct olevariantdata *pvar;
08680     SAFEARRAYBOUND *psab = NULL;
08681     SAFEARRAY *psa = NULL;
08682     UINT dim = 0;
08683     UINT i = 0;
08684 
08685     ole_initialize();
08686 
08687     vt = NUM2UINT(vvt);
08688     vt = (vt | VT_ARRAY);
08689     Check_Type(elems, T_ARRAY);
08690     obj = folevariant_s_allocate(klass);
08691 
08692     Data_Get_Struct(obj, struct olevariantdata, pvar);
08693     dim = RARRAY_LEN(elems);
08694 
08695     psab = ALLOC_N(SAFEARRAYBOUND, dim);
08696 
08697     if(!psab) {
08698         rb_raise(rb_eRuntimeError, "memory allocation error");
08699     }
08700 
08701     for (i = 0; i < dim; i++) {
08702         psab[i].cElements = FIX2INT(rb_ary_entry(elems, i));
08703         psab[i].lLbound = 0;
08704     }
08705 
08706     psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
08707     if (psa == NULL) {
08708         if (psab) free(psab);
08709         rb_raise(rb_eRuntimeError, "memory allocation error(SafeArrayCreate)");
08710     }
08711 
08712     V_VT(&(pvar->var)) = vt;
08713     if (vt & VT_BYREF) {
08714         V_VT(&(pvar->realvar)) = (vt & ~VT_BYREF);
08715         V_ARRAY(&(pvar->realvar)) = psa;
08716         V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
08717     } else {
08718         V_ARRAY(&(pvar->var)) = psa;
08719     }
08720     if (psab) free(psab);
08721     return obj;
08722 }
08723 
08724 /*
08725  *  call-seq:
08726  *     WIN32OLE_VARIANT.new(val, vartype) #=> WIN32OLE_VARIANT object.
08727  *
08728  *  Returns Ruby object wrapping OLE variant.
08729  *  The first argument specifies Ruby object to convert OLE variant variable.
08730  *  The second argument specifies VARIANT type.
08731  *  In some situation, you need the WIN32OLE_VARIANT object to pass OLE method
08732  *
08733  *     shell = WIN32OLE.new("Shell.Application")
08734  *     folder = shell.NameSpace("C:\\Windows")
08735  *     item = folder.ParseName("tmp.txt")
08736  *     # You can't use Ruby String object to call FolderItem.InvokeVerb.
08737  *     # Instead, you have to use WIN32OLE_VARIANT object to call the method.
08738  *     shortcut = WIN32OLE_VARIANT.new("Create Shortcut(\&S)")
08739  *     item.invokeVerb(shortcut)
08740  *
08741  */
08742 static VALUE
08743 folevariant_initialize(VALUE self, VALUE args)
08744 {
08745     int len = 0;
08746     VARIANT var;
08747     VALUE val;
08748     VALUE vvt;
08749     VARTYPE vt;
08750     struct olevariantdata *pvar;
08751 
08752     len = RARRAY_LEN(args);
08753     if (len < 1 || len > 3) {
08754         rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", len);
08755     }
08756     VariantInit(&var);
08757     val = rb_ary_entry(args, 0);
08758 
08759     if(!rb_obj_is_kind_of(val, cWIN32OLE) &&
08760        !rb_obj_is_kind_of(val, cWIN32OLE_VARIANT) &&
08761        !rb_obj_is_kind_of(val, rb_cTime)) {
08762         switch (TYPE(val)) {
08763         case T_ARRAY:
08764         case T_STRING:
08765         case T_FIXNUM:
08766         case T_BIGNUM:
08767         case T_FLOAT:
08768         case T_TRUE:
08769         case T_FALSE:
08770         case T_NIL:
08771             break;
08772         default:
08773             rb_raise(rb_eTypeError, "can not convert WIN32OLE_VARIANT from type %s",
08774                      rb_obj_classname(val));
08775         }
08776     }
08777 
08778     Data_Get_Struct(self, struct olevariantdata, pvar);
08779     if (len == 1) {
08780         ole_val2variant(val, &(pvar->var));
08781     } else {
08782         vvt = rb_ary_entry(args, 1);
08783         vt = NUM2INT(vvt);
08784         ole_val2olevariantdata(val, vt, pvar);
08785     }
08786     vt = V_VT(&pvar->var);
08787     return self;
08788 }
08789 
08790 static SAFEARRAY *
08791 get_locked_safe_array(VALUE val)
08792 {
08793     struct olevariantdata *pvar;
08794     SAFEARRAY *psa = NULL;
08795     HRESULT hr;
08796     Data_Get_Struct(val, struct olevariantdata, pvar);
08797     if (!(V_VT(&(pvar->var)) & VT_ARRAY)) {
08798         rb_raise(rb_eTypeError, "variant type is not VT_ARRAY.");
08799     }
08800     psa = V_ISBYREF(&(pvar->var)) ? *V_ARRAYREF(&(pvar->var)) : V_ARRAY(&(pvar->var));
08801     if (psa == NULL) {
08802         return psa;
08803     }
08804     hr = SafeArrayLock(psa);
08805     if (FAILED(hr)) {
08806         ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayLock");
08807     }
08808     return psa;
08809 }
08810 
08811 static long *
08812 ary2safe_array_index(int ary_size, VALUE *ary, SAFEARRAY *psa)
08813 {
08814     long dim;
08815     long *pid;
08816     long i;
08817     dim = SafeArrayGetDim(psa);
08818     if (dim != ary_size) {
08819         rb_raise(rb_eArgError, "unmatch number of indices");
08820     }
08821     pid = ALLOC_N(long, dim);
08822     if (pid == NULL) {
08823         rb_raise(rb_eRuntimeError, "failed to allocate memory for indices");
08824     }
08825     for (i = 0; i < dim; i++) {
08826         pid[i] = NUM2INT(ary[i]);
08827     }
08828     return pid;
08829 }
08830 
08831 static void
08832 unlock_safe_array(SAFEARRAY *psa)
08833 {
08834     HRESULT hr;
08835     hr = SafeArrayUnlock(psa);
08836     if (FAILED(hr)) {
08837         ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayUnlock");
08838     }
08839 }
08840 
08841 /*
08842  *  call-seq:
08843  *     WIN32OLE_VARIANT[i,j,...] #=> element of OLE array.
08844  *
08845  *  Returns the element of WIN32OLE_VARIANT object(OLE array).
08846  *  This method is available only when the variant type of
08847  *  WIN32OLE_VARIANT object is VT_ARRAY.
08848  *
08849  *  REMARK:
08850  *     The all indicies should be 0 or natural number and
08851  *     lower than or equal to max indicies.
08852  *     (This point is different with Ruby Array indicies.)
08853  *
08854  *     obj = WIN32OLE_VARIANT.new([[1,2,3],[4,5,6]])
08855  *     p obj[0,0] # => 1
08856  *     p obj[1,0] # => 4
08857  *     p obj[2,0] # => WIN32OLERuntimeError
08858  *     p obj[0, -1] # => WIN32OLERuntimeError
08859  *
08860  */
08861 static VALUE
08862 folevariant_ary_aref(int argc, VALUE *argv, VALUE self)
08863 {
08864     struct olevariantdata *pvar;
08865     SAFEARRAY *psa;
08866     VALUE val = Qnil;
08867     VARIANT variant;
08868     long *pid;
08869     HRESULT hr;
08870 
08871     Data_Get_Struct(self, struct olevariantdata, pvar);
08872     if (!V_ISARRAY(&(pvar->var))) {
08873         rb_raise(eWIN32OLERuntimeError,
08874                  "`[]' is not available for this variant type object");
08875     }
08876     psa = get_locked_safe_array(self);
08877     if (psa == NULL) {
08878         return val;
08879     }
08880 
08881     pid = ary2safe_array_index(argc, argv, psa);
08882 
08883     VariantInit(&variant);
08884     V_VT(&variant) = (V_VT(&(pvar->var)) & ~VT_ARRAY) | VT_BYREF;
08885     hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
08886     if (FAILED(hr)) {
08887         ole_raise(hr, eWIN32OLERuntimeError, "failed to SafeArrayPtrOfIndex");
08888     }
08889     val = ole_variant2val(&variant);
08890 
08891     unlock_safe_array(psa);
08892     if (pid) free(pid);
08893     return val;
08894 }
08895 
08896 static VOID *
08897 val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt)
08898 {
08899     VOID *p = NULL;
08900     HRESULT hr = S_OK;
08901     ole_val2variant_ex(val, var, vt);
08902     if ((vt & ~VT_BYREF) == VT_VARIANT) {
08903         p = var;
08904     } else {
08905         if ( (vt & ~VT_BYREF) != V_VT(var)) {
08906             hr = VariantChangeTypeEx(var, var,
08907                     cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF));
08908             if (FAILED(hr)) {
08909                 ole_raise(hr, rb_eRuntimeError, "failed to change type");
08910             }
08911         }
08912         p = get_ptr_of_variant(var);
08913     }
08914     if (p == NULL) {
08915         rb_raise(rb_eRuntimeError, "failed to get pointer of variant");
08916     }
08917     return p;
08918 }
08919 
08920 /*
08921  *  call-seq:
08922  *     WIN32OLE_VARIANT[i,j,...] = val #=> set the element of OLE array
08923  *
08924  *  Set the element of WIN32OLE_VARIANT object(OLE array) to val.
08925  *  This method is available only when the variant type of
08926  *  WIN32OLE_VARIANT object is VT_ARRAY.
08927  *
08928  *  REMARK:
08929  *     The all indicies should be 0 or natural number and
08930  *     lower than or equal to max indicies.
08931  *     (This point is different with Ruby Array indicies.)
08932  *
08933  *     obj = WIN32OLE_VARIANT.new([[1,2,3],[4,5,6]])
08934  *     obj[0,0] = 7
08935  *     obj[1,0] = 8
08936  *     p obj.value # => [[7,2,3], [8,5,6]]
08937  *     obj[2,0] = 9 # => WIN32OLERuntimeError
08938  *     obj[0, -1] = 9 # => WIN32OLERuntimeError
08939  *
08940  */
08941 static VALUE
08942 folevariant_ary_aset(int argc, VALUE *argv, VALUE self)
08943 {
08944     struct olevariantdata *pvar;
08945     SAFEARRAY *psa;
08946     VARIANT var;
08947     VARTYPE vt;
08948     long *pid;
08949     HRESULT hr;
08950     VOID *p = NULL;
08951 
08952     Data_Get_Struct(self, struct olevariantdata, pvar);
08953     if (!V_ISARRAY(&(pvar->var))) {
08954         rb_raise(eWIN32OLERuntimeError,
08955                  "`[]' is not available for this variant type object");
08956     }
08957     psa = get_locked_safe_array(self);
08958     if (psa == NULL) {
08959         rb_raise(rb_eRuntimeError, "failed to get SafeArray pointer");
08960     }
08961 
08962     pid = ary2safe_array_index(argc-1, argv, psa);
08963 
08964     VariantInit(&var);
08965     vt = (V_VT(&(pvar->var)) & ~VT_ARRAY);
08966     p = val2variant_ptr(argv[argc-1], &var, vt);
08967     if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
08968         (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
08969         rb_raise(eWIN32OLERuntimeError, "argument does not have IDispatch or IUnknown Interface");
08970     }
08971     hr = SafeArrayPutElement(psa, pid, p);
08972     if (FAILED(hr)) {
08973         ole_raise(hr, eWIN32OLERuntimeError, "failed to SafeArrayPutElement");
08974     }
08975 
08976     unlock_safe_array(psa);
08977     if (pid) free(pid);
08978     return argv[argc-1];
08979 }
08980 
08981 /*
08982  *  call-seq:
08983  *     WIN32OLE_VARIANT.value #=> Ruby object.
08984  *
08985  *  Returns Ruby object value from OLE variant.
08986  *     obj = WIN32OLE_VARIANT.new(1, WIN32OLE::VARIANT::VT_BSTR)
08987  *     obj.value # => "1" (not Fixnum object, but String object "1")
08988  *
08989  */
08990 static VALUE
08991 folevariant_value(VALUE self)
08992 {
08993     struct olevariantdata *pvar;
08994     VALUE val = Qnil;
08995     VARTYPE vt;
08996     int dim;
08997     SAFEARRAY *psa;
08998     Data_Get_Struct(self, struct olevariantdata, pvar);
08999 
09000     val = ole_variant2val(&(pvar->var));
09001     vt = V_VT(&(pvar->var));
09002 
09003     if ((vt & ~VT_BYREF) == (VT_UI1|VT_ARRAY)) {
09004         if (vt & VT_BYREF) {
09005             psa = *V_ARRAYREF(&(pvar->var));
09006         } else {
09007             psa  = V_ARRAY(&(pvar->var));
09008         }
09009         if (!psa) {
09010             return val;
09011         }
09012         dim = SafeArrayGetDim(psa);
09013         if (dim == 1) {
09014             val = rb_funcall(val, rb_intern("pack"), 1, rb_str_new2("C*"));
09015         }
09016     }
09017     return val;
09018 }
09019 
09020 /*
09021  *  call-seq:
09022  *     WIN32OLE_VARIANT.vartype #=> OLE variant type.
09023  *
09024  *  Returns OLE variant type.
09025  *     obj = WIN32OLE_VARIANT.new("string")
09026  *     obj.vartype # => WIN32OLE::VARIANT::VT_BSTR
09027  *
09028  */
09029 static VALUE
09030 folevariant_vartype(VALUE self)
09031 {
09032     struct olevariantdata *pvar;
09033     Data_Get_Struct(self, struct olevariantdata, pvar);
09034     return INT2FIX(V_VT(&pvar->var));
09035 }
09036 
09037 /*
09038  *  call-seq:
09039  *     WIN32OLE_VARIANT.value = val #=> set WIN32OLE_VARIANT value to val.
09040  *
09041  *  Sets variant value to val. If the val type does not match variant value
09042  *  type(vartype), then val is changed to match variant value type(vartype)
09043  *  before setting val.
09044  *  Thie method is not available when vartype is VT_ARRAY(except VT_UI1|VT_ARRAY).
09045  *  If the vartype is VT_UI1|VT_ARRAY, the val should be String object.
09046  *
09047  *     obj = WIN32OLE_VARIANT.new(1) # obj.vartype is WIN32OLE::VARIANT::VT_I4
09048  *     obj.value = 3.2 # 3.2 is changed to 3 when setting value.
09049  *     p obj.value # => 3
09050  */
09051 static VALUE
09052 folevariant_set_value(VALUE self, VALUE val)
09053 {
09054     struct olevariantdata *pvar;
09055     VARTYPE vt;
09056     Data_Get_Struct(self, struct olevariantdata, pvar);
09057     vt = V_VT(&(pvar->var));
09058     if (V_ISARRAY(&(pvar->var)) && ((vt & ~VT_BYREF) != (VT_UI1|VT_ARRAY) || TYPE(val) != T_STRING)) {
09059         rb_raise(eWIN32OLERuntimeError,
09060                  "`value=' is not available for this variant type object");
09061     }
09062     ole_val2olevariantdata(val, vt, pvar);
09063     return Qnil;
09064 }
09065 
09066 static void
09067 init_enc2cp(void)
09068 {
09069     enc2cp_table = st_init_numtable();
09070 }
09071 
09072 static void
09073 free_enc2cp(void)
09074 {
09075     st_free_table(enc2cp_table);
09076 }
09077 
09078 void
09079 Init_win32ole(void)
09080 {
09081     g_ole_initialized_init();
09082     ary_ole_event = rb_ary_new();
09083     rb_gc_register_mark_object(ary_ole_event);
09084     id_events = rb_intern("events");
09085 
09086     com_vtbl.QueryInterface = QueryInterface;
09087     com_vtbl.AddRef = AddRef;
09088     com_vtbl.Release = Release;
09089     com_vtbl.GetTypeInfoCount = GetTypeInfoCount;
09090     com_vtbl.GetTypeInfo = GetTypeInfo;
09091     com_vtbl.GetIDsOfNames = GetIDsOfNames;
09092     com_vtbl.Invoke = Invoke;
09093 
09094     message_filter.QueryInterface = mf_QueryInterface;
09095     message_filter.AddRef = mf_AddRef;
09096     message_filter.Release = mf_Release;
09097     message_filter.HandleInComingCall = mf_HandleInComingCall;
09098     message_filter.RetryRejectedCall = mf_RetryRejectedCall;
09099     message_filter.MessagePending = mf_MessagePending;
09100 
09101     com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable());
09102     rb_gc_register_mark_object(com_hash);
09103 
09104     cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
09105 
09106     rb_define_alloc_func(cWIN32OLE, fole_s_allocate);
09107 
09108     rb_define_method(cWIN32OLE, "initialize", fole_initialize, -1);
09109 
09110     rb_define_singleton_method(cWIN32OLE, "connect", fole_s_connect, -1);
09111     rb_define_singleton_method(cWIN32OLE, "const_load", fole_s_const_load, -1);
09112 
09113     rb_define_singleton_method(cWIN32OLE, "ole_free", fole_s_free, 1);
09114     rb_define_singleton_method(cWIN32OLE, "ole_reference_count", fole_s_reference_count, 1);
09115     rb_define_singleton_method(cWIN32OLE, "ole_show_help", fole_s_show_help, -1);
09116     rb_define_singleton_method(cWIN32OLE, "codepage", fole_s_get_code_page, 0);
09117     rb_define_singleton_method(cWIN32OLE, "codepage=", fole_s_set_code_page, 1);
09118     rb_define_singleton_method(cWIN32OLE, "locale", fole_s_get_locale, 0);
09119     rb_define_singleton_method(cWIN32OLE, "locale=", fole_s_set_locale, 1);
09120     rb_define_singleton_method(cWIN32OLE, "create_guid", fole_s_create_guid, 0);
09121     rb_define_singleton_method(cWIN32OLE, "ole_initialize", fole_s_ole_initialize, 0);
09122     rb_define_singleton_method(cWIN32OLE, "ole_uninitialize", fole_s_ole_uninitialize, 0);
09123 
09124     rb_define_method(cWIN32OLE, "invoke", fole_invoke, -1);
09125     rb_define_method(cWIN32OLE, "[]", fole_getproperty_with_bracket, -1);
09126     rb_define_method(cWIN32OLE, "_invoke", fole_invoke2, 3);
09127     rb_define_method(cWIN32OLE, "_getproperty", fole_getproperty2, 3);
09128     rb_define_method(cWIN32OLE, "_setproperty", fole_setproperty2, 3);
09129 
09130     /* support propput method that takes an argument */
09131     rb_define_method(cWIN32OLE, "[]=", fole_setproperty_with_bracket, -1);
09132 
09133     rb_define_method(cWIN32OLE, "ole_free", fole_free, 0);
09134 
09135     rb_define_method(cWIN32OLE, "each", fole_each, 0);
09136     rb_define_method(cWIN32OLE, "method_missing", fole_missing, -1);
09137 
09138     /* support setproperty method much like Perl ;-) */
09139     rb_define_method(cWIN32OLE, "setproperty", fole_setproperty, -1);
09140 
09141     rb_define_method(cWIN32OLE, "ole_methods", fole_methods, 0);
09142     rb_define_method(cWIN32OLE, "ole_get_methods", fole_get_methods, 0);
09143     rb_define_method(cWIN32OLE, "ole_put_methods", fole_put_methods, 0);
09144     rb_define_method(cWIN32OLE, "ole_func_methods", fole_func_methods, 0);
09145 
09146     rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1);
09147     rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method");
09148     rb_define_method(cWIN32OLE, "ole_activex_initialize", fole_activex_initialize, 0);
09149     rb_define_method(cWIN32OLE, "ole_type", fole_type, 0);
09150     rb_define_alias(cWIN32OLE, "ole_obj_help", "ole_type");
09151     rb_define_method(cWIN32OLE, "ole_typelib", fole_typelib, 0);
09152     rb_define_method(cWIN32OLE, "ole_query_interface", fole_query_interface, 1);
09153     rb_define_method(cWIN32OLE, "ole_respond_to?", fole_respond_to, 1);
09154 
09155     rb_define_const(cWIN32OLE, "VERSION", rb_str_new2(WIN32OLE_VERSION));
09156     rb_define_const(cWIN32OLE, "ARGV", rb_ary_new());
09157 
09158     rb_define_const(cWIN32OLE, "CP_ACP", INT2FIX(CP_ACP));
09159     rb_define_const(cWIN32OLE, "CP_OEMCP", INT2FIX(CP_OEMCP));
09160     rb_define_const(cWIN32OLE, "CP_MACCP", INT2FIX(CP_MACCP));
09161     rb_define_const(cWIN32OLE, "CP_THREAD_ACP", INT2FIX(CP_THREAD_ACP));
09162     rb_define_const(cWIN32OLE, "CP_SYMBOL", INT2FIX(CP_SYMBOL));
09163     rb_define_const(cWIN32OLE, "CP_UTF7", INT2FIX(CP_UTF7));
09164     rb_define_const(cWIN32OLE, "CP_UTF8", INT2FIX(CP_UTF8));
09165 
09166     rb_define_const(cWIN32OLE, "LOCALE_SYSTEM_DEFAULT", INT2FIX(LOCALE_SYSTEM_DEFAULT));
09167     rb_define_const(cWIN32OLE, "LOCALE_USER_DEFAULT", INT2FIX(LOCALE_USER_DEFAULT));
09168 
09169     mWIN32OLE_VARIANT = rb_define_module_under(cWIN32OLE, "VARIANT");
09170     rb_define_const(mWIN32OLE_VARIANT, "VT_EMPTY", INT2FIX(VT_EMPTY));
09171     rb_define_const(mWIN32OLE_VARIANT, "VT_NULL", INT2FIX(VT_NULL));
09172     rb_define_const(mWIN32OLE_VARIANT, "VT_I2", INT2FIX(VT_I2));
09173     rb_define_const(mWIN32OLE_VARIANT, "VT_I4", INT2FIX(VT_I4));
09174     rb_define_const(mWIN32OLE_VARIANT, "VT_R4", INT2FIX(VT_R4));
09175     rb_define_const(mWIN32OLE_VARIANT, "VT_R8", INT2FIX(VT_R8));
09176     rb_define_const(mWIN32OLE_VARIANT, "VT_CY", INT2FIX(VT_CY));
09177     rb_define_const(mWIN32OLE_VARIANT, "VT_DATE", INT2FIX(VT_DATE));
09178     rb_define_const(mWIN32OLE_VARIANT, "VT_BSTR", INT2FIX(VT_BSTR));
09179     rb_define_const(mWIN32OLE_VARIANT, "VT_USERDEFINED", INT2FIX(VT_USERDEFINED));
09180     rb_define_const(mWIN32OLE_VARIANT, "VT_PTR", INT2FIX(VT_PTR));
09181     rb_define_const(mWIN32OLE_VARIANT, "VT_DISPATCH", INT2FIX(VT_DISPATCH));
09182     rb_define_const(mWIN32OLE_VARIANT, "VT_ERROR", INT2FIX(VT_ERROR));
09183     rb_define_const(mWIN32OLE_VARIANT, "VT_BOOL", INT2FIX(VT_BOOL));
09184     rb_define_const(mWIN32OLE_VARIANT, "VT_VARIANT", INT2FIX(VT_VARIANT));
09185     rb_define_const(mWIN32OLE_VARIANT, "VT_UNKNOWN", INT2FIX(VT_UNKNOWN));
09186     rb_define_const(mWIN32OLE_VARIANT, "VT_I1", INT2FIX(VT_I1));
09187     rb_define_const(mWIN32OLE_VARIANT, "VT_UI1", INT2FIX(VT_UI1));
09188     rb_define_const(mWIN32OLE_VARIANT, "VT_UI2", INT2FIX(VT_UI2));
09189     rb_define_const(mWIN32OLE_VARIANT, "VT_UI4", INT2FIX(VT_UI4));
09190 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
09191     rb_define_const(mWIN32OLE_VARIANT, "VT_I8", INT2FIX(VT_I8));
09192     rb_define_const(mWIN32OLE_VARIANT, "VT_UI8", INT2FIX(VT_UI8));
09193 #endif
09194     rb_define_const(mWIN32OLE_VARIANT, "VT_INT", INT2FIX(VT_INT));
09195     rb_define_const(mWIN32OLE_VARIANT, "VT_UINT", INT2FIX(VT_UINT));
09196     rb_define_const(mWIN32OLE_VARIANT, "VT_ARRAY", INT2FIX(VT_ARRAY));
09197     rb_define_const(mWIN32OLE_VARIANT, "VT_BYREF", INT2FIX(VT_BYREF));
09198 
09199     cWIN32OLE_TYPELIB = rb_define_class("WIN32OLE_TYPELIB", rb_cObject);
09200     rb_define_singleton_method(cWIN32OLE_TYPELIB, "typelibs", foletypelib_s_typelibs, 0);
09201     rb_define_alloc_func(cWIN32OLE_TYPELIB, foletypelib_s_allocate);
09202     rb_define_method(cWIN32OLE_TYPELIB, "initialize", foletypelib_initialize, -2);
09203     rb_define_method(cWIN32OLE_TYPELIB, "guid", foletypelib_guid, 0);
09204     rb_define_method(cWIN32OLE_TYPELIB, "name", foletypelib_name, 0);
09205     rb_define_method(cWIN32OLE_TYPELIB, "version", foletypelib_version, 0);
09206     rb_define_method(cWIN32OLE_TYPELIB, "major_version", foletypelib_major_version, 0);
09207     rb_define_method(cWIN32OLE_TYPELIB, "minor_version", foletypelib_minor_version, 0);
09208     rb_define_method(cWIN32OLE_TYPELIB, "path", foletypelib_path, 0);
09209     rb_define_method(cWIN32OLE_TYPELIB, "ole_types", foletypelib_ole_types, 0);
09210     rb_define_alias(cWIN32OLE_TYPELIB, "ole_classes", "ole_types");
09211     rb_define_method(cWIN32OLE_TYPELIB, "visible?", foletypelib_visible, 0);
09212     rb_define_method(cWIN32OLE_TYPELIB, "library_name", foletypelib_library_name, 0);
09213     rb_define_alias(cWIN32OLE_TYPELIB, "to_s", "name");
09214     rb_define_method(cWIN32OLE_TYPELIB, "inspect", foletypelib_inspect, 0);
09215 
09216     cWIN32OLE_TYPE = rb_define_class("WIN32OLE_TYPE", rb_cObject);
09217     rb_define_singleton_method(cWIN32OLE_TYPE, "ole_classes", foletype_s_ole_classes, 1);
09218     rb_define_singleton_method(cWIN32OLE_TYPE, "typelibs", foletype_s_typelibs, 0);
09219     rb_define_singleton_method(cWIN32OLE_TYPE, "progids", foletype_s_progids, 0);
09220     rb_define_alloc_func(cWIN32OLE_TYPE, foletype_s_allocate);
09221     rb_define_method(cWIN32OLE_TYPE, "initialize", foletype_initialize, 2);
09222     rb_define_method(cWIN32OLE_TYPE, "name", foletype_name, 0);
09223     rb_define_method(cWIN32OLE_TYPE, "ole_type", foletype_ole_type, 0);
09224     rb_define_method(cWIN32OLE_TYPE, "guid", foletype_guid, 0);
09225     rb_define_method(cWIN32OLE_TYPE, "progid", foletype_progid, 0);
09226     rb_define_method(cWIN32OLE_TYPE, "visible?", foletype_visible, 0);
09227     rb_define_alias(cWIN32OLE_TYPE, "to_s", "name");
09228     rb_define_method(cWIN32OLE_TYPE, "major_version", foletype_major_version, 0);
09229     rb_define_method(cWIN32OLE_TYPE, "minor_version", foletype_minor_version, 0);
09230     rb_define_method(cWIN32OLE_TYPE, "typekind", foletype_typekind, 0);
09231     rb_define_method(cWIN32OLE_TYPE, "helpstring", foletype_helpstring, 0);
09232     rb_define_method(cWIN32OLE_TYPE, "src_type", foletype_src_type, 0);
09233     rb_define_method(cWIN32OLE_TYPE, "helpfile", foletype_helpfile, 0);
09234     rb_define_method(cWIN32OLE_TYPE, "helpcontext", foletype_helpcontext, 0);
09235     rb_define_method(cWIN32OLE_TYPE, "variables", foletype_variables, 0);
09236     rb_define_method(cWIN32OLE_TYPE, "ole_methods", foletype_methods, 0);
09237     rb_define_method(cWIN32OLE_TYPE, "ole_typelib", foletype_ole_typelib, 0);
09238     rb_define_method(cWIN32OLE_TYPE, "implemented_ole_types", foletype_impl_ole_types, 0);
09239     rb_define_method(cWIN32OLE_TYPE, "source_ole_types", foletype_source_ole_types, 0);
09240     rb_define_method(cWIN32OLE_TYPE, "default_event_sources", foletype_default_event_sources, 0);
09241     rb_define_method(cWIN32OLE_TYPE, "default_ole_types", foletype_default_ole_types, 0);
09242     rb_define_method(cWIN32OLE_TYPE, "inspect", foletype_inspect, 0);
09243 
09244     cWIN32OLE_VARIABLE = rb_define_class("WIN32OLE_VARIABLE", rb_cObject);
09245     rb_define_method(cWIN32OLE_VARIABLE, "name", folevariable_name, 0);
09246     rb_define_method(cWIN32OLE_VARIABLE, "ole_type", folevariable_ole_type, 0);
09247     rb_define_method(cWIN32OLE_VARIABLE, "ole_type_detail", folevariable_ole_type_detail, 0);
09248     rb_define_method(cWIN32OLE_VARIABLE, "value", folevariable_value, 0);
09249     rb_define_method(cWIN32OLE_VARIABLE, "visible?", folevariable_visible, 0);
09250     rb_define_method(cWIN32OLE_VARIABLE, "variable_kind", folevariable_variable_kind, 0);
09251     rb_define_method(cWIN32OLE_VARIABLE, "varkind", folevariable_varkind, 0);
09252     rb_define_method(cWIN32OLE_VARIABLE, "inspect", folevariable_inspect, 0);
09253     rb_define_alias(cWIN32OLE_VARIABLE, "to_s", "name");
09254 
09255     cWIN32OLE_METHOD = rb_define_class("WIN32OLE_METHOD", rb_cObject);
09256     rb_define_alloc_func(cWIN32OLE_METHOD, folemethod_s_allocate);
09257     rb_define_method(cWIN32OLE_METHOD, "initialize", folemethod_initialize, 2);
09258     rb_define_method(cWIN32OLE_METHOD, "name", folemethod_name, 0);
09259     rb_define_method(cWIN32OLE_METHOD, "return_type", folemethod_return_type, 0);
09260     rb_define_method(cWIN32OLE_METHOD, "return_vtype", folemethod_return_vtype, 0);
09261     rb_define_method(cWIN32OLE_METHOD, "return_type_detail", folemethod_return_type_detail, 0);
09262     rb_define_method(cWIN32OLE_METHOD, "invoke_kind", folemethod_invoke_kind, 0);
09263     rb_define_method(cWIN32OLE_METHOD, "invkind", folemethod_invkind, 0);
09264     rb_define_method(cWIN32OLE_METHOD, "visible?", folemethod_visible, 0);
09265     rb_define_method(cWIN32OLE_METHOD, "event?", folemethod_event, 0);
09266     rb_define_method(cWIN32OLE_METHOD, "event_interface", folemethod_event_interface, 0);
09267     rb_define_method(cWIN32OLE_METHOD, "helpstring", folemethod_helpstring, 0);
09268     rb_define_method(cWIN32OLE_METHOD, "helpfile", folemethod_helpfile, 0);
09269     rb_define_method(cWIN32OLE_METHOD, "helpcontext", folemethod_helpcontext, 0);
09270     rb_define_method(cWIN32OLE_METHOD, "dispid", folemethod_dispid, 0);
09271     rb_define_method(cWIN32OLE_METHOD, "offset_vtbl", folemethod_offset_vtbl, 0);
09272     rb_define_method(cWIN32OLE_METHOD, "size_params", folemethod_size_params, 0);
09273     rb_define_method(cWIN32OLE_METHOD, "size_opt_params", folemethod_size_opt_params, 0);
09274     rb_define_method(cWIN32OLE_METHOD, "params", folemethod_params, 0);
09275     rb_define_alias(cWIN32OLE_METHOD, "to_s", "name");
09276     rb_define_method(cWIN32OLE_METHOD, "inspect", folemethod_inspect, 0);
09277 
09278     cWIN32OLE_PARAM = rb_define_class("WIN32OLE_PARAM", rb_cObject);
09279     rb_define_alloc_func(cWIN32OLE_PARAM, foleparam_s_allocate);
09280     rb_define_method(cWIN32OLE_PARAM, "initialize", foleparam_initialize, 2);
09281     rb_define_method(cWIN32OLE_PARAM, "name", foleparam_name, 0);
09282     rb_define_method(cWIN32OLE_PARAM, "ole_type", foleparam_ole_type, 0);
09283     rb_define_method(cWIN32OLE_PARAM, "ole_type_detail", foleparam_ole_type_detail, 0);
09284     rb_define_method(cWIN32OLE_PARAM, "input?", foleparam_input, 0);
09285     rb_define_method(cWIN32OLE_PARAM, "output?", foleparam_output, 0);
09286     rb_define_method(cWIN32OLE_PARAM, "optional?", foleparam_optional, 0);
09287     rb_define_method(cWIN32OLE_PARAM, "retval?", foleparam_retval, 0);
09288     rb_define_method(cWIN32OLE_PARAM, "default", foleparam_default, 0);
09289     rb_define_alias(cWIN32OLE_PARAM, "to_s", "name");
09290     rb_define_method(cWIN32OLE_PARAM, "inspect", foleparam_inspect, 0);
09291 
09292     cWIN32OLE_EVENT = rb_define_class("WIN32OLE_EVENT", rb_cObject);
09293     rb_define_singleton_method(cWIN32OLE_EVENT, "message_loop", fev_s_msg_loop, 0);
09294     rb_define_alloc_func(cWIN32OLE_EVENT, fev_s_allocate);
09295     rb_define_method(cWIN32OLE_EVENT, "initialize", fev_initialize, -1);
09296     rb_define_method(cWIN32OLE_EVENT, "on_event", fev_on_event, -1);
09297     rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1);
09298     rb_define_method(cWIN32OLE_EVENT, "off_event", fev_off_event, -1);
09299     rb_define_method(cWIN32OLE_EVENT, "unadvise", fev_unadvise, 0);
09300     rb_define_method(cWIN32OLE_EVENT, "handler=", fev_set_handler, 1);
09301     rb_define_method(cWIN32OLE_EVENT, "handler", fev_get_handler, 0);
09302 
09303     cWIN32OLE_VARIANT = rb_define_class("WIN32OLE_VARIANT", rb_cObject);
09304     rb_define_alloc_func(cWIN32OLE_VARIANT, folevariant_s_allocate);
09305     rb_define_singleton_method(cWIN32OLE_VARIANT, "array", folevariant_s_array, 2);
09306     rb_define_method(cWIN32OLE_VARIANT, "initialize", folevariant_initialize, -2);
09307     rb_define_method(cWIN32OLE_VARIANT, "value", folevariant_value, 0);
09308     rb_define_method(cWIN32OLE_VARIANT, "value=", folevariant_set_value, 1);
09309     rb_define_method(cWIN32OLE_VARIANT, "vartype", folevariant_vartype, 0);
09310     rb_define_method(cWIN32OLE_VARIANT, "[]", folevariant_ary_aref, -1);
09311     rb_define_method(cWIN32OLE_VARIANT, "[]=", folevariant_ary_aset, -1);
09312     rb_define_const(cWIN32OLE_VARIANT, "Empty", rb_funcall(cWIN32OLE_VARIANT, rb_intern("new"), 2, Qnil, INT2FIX(VT_EMPTY)));
09313     rb_define_const(cWIN32OLE_VARIANT, "Null", rb_funcall(cWIN32OLE_VARIANT, rb_intern("new"), 2, Qnil, INT2FIX(VT_NULL)));
09314     rb_define_const(cWIN32OLE_VARIANT, "Nothing", rb_funcall(cWIN32OLE_VARIANT, rb_intern("new"), 2, Qnil, INT2FIX(VT_DISPATCH)));
09315 
09316     eWIN32OLERuntimeError = rb_define_class("WIN32OLERuntimeError", rb_eRuntimeError);
09317 
09318     init_enc2cp();
09319     atexit((void (*)(void))free_enc2cp);
09320     ole_init_cp();
09321 }
09322