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