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