Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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