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