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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7